git: ae16cbfdd2a1 - main - gicv3: Use an offset to find the redist registers

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Wed, 31 May 2023 14:20:14 UTC
The branch main has been updated by andrew:

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

commit ae16cbfdd2a1821f69d166c4fc4cdbb4b8d5ef62
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2023-05-25 08:22:03 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2023-05-31 14:10:41 +0000

    gicv3: Use an offset to find the redist registers
    
    To find the redistributor registers use the resource we have already
    found and add an offset. This removed the need to create a
    per-redistributor resource as it can now be a pointer to the resource
    found in attach.
    
    While here check the offset is within the bounds of the resource. Some
    ACPI tables list each redistributor as a separate memory range, even
    if they are physically contiguous. In this case we may not have each
    resource virtually contiguous with neighbouring resources. This can
    lead to a data abort when reading past the resource range.
    
    Reviewed by:    kevans
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D40263
---
 sys/arm64/arm64/gic_v3.c     | 41 ++++++++++++++++++++++++-----------------
 sys/arm64/arm64/gic_v3_var.h | 12 +++++++-----
 sys/arm64/arm64/gicv3_its.c  |  3 ++-
 3 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c
index e9754797d095..d108cabfe4d9 100644
--- a/sys/arm64/arm64/gic_v3.c
+++ b/sys/arm64/arm64/gic_v3.c
@@ -226,7 +226,8 @@ gic_r_read_4(device_t dev, bus_size_t offset)
 	struct resource *rdist;
 
 	sc = device_get_softc(dev);
-	rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset;
 	return (bus_read_4(rdist, offset));
 }
 
@@ -237,7 +238,8 @@ gic_r_read_8(device_t dev, bus_size_t offset)
 	struct resource *rdist;
 
 	sc = device_get_softc(dev);
-	rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset;
 	return (bus_read_8(rdist, offset));
 }
 
@@ -248,7 +250,8 @@ gic_r_write_4(device_t dev, bus_size_t offset, uint32_t val)
 	struct resource *rdist;
 
 	sc = device_get_softc(dev);
-	rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset;
 	bus_write_4(rdist, offset, val);
 }
 
@@ -259,7 +262,8 @@ gic_r_write_8(device_t dev, bus_size_t offset, uint64_t val)
 	struct resource *rdist;
 
 	sc = device_get_softc(dev);
-	rdist = &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	rdist = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res;
+	offset += sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset;
 	bus_write_8(rdist, offset, val);
 }
 
@@ -1215,6 +1219,7 @@ static void
 gic_v3_wait_for_rwp(struct gic_v3_softc *sc, enum gic_v3_xdist xdist)
 {
 	struct resource *res;
+	bus_size_t offset;
 	u_int cpuid;
 	size_t us_left = 1000000;
 
@@ -1223,16 +1228,18 @@ gic_v3_wait_for_rwp(struct gic_v3_softc *sc, enum gic_v3_xdist xdist)
 	switch (xdist) {
 	case DIST:
 		res = sc->gic_dist;
+		offset = 0;
 		break;
 	case REDIST:
-		res = &sc->gic_redists.pcpu[cpuid]->res;
+		res = sc->gic_redists.pcpu[cpuid]->res;
+		offset = sc->gic_redists.pcpu[PCPU_GET(cpuid)]->offset;
 		break;
 	default:
 		KASSERT(0, ("%s: Attempt to wait for unknown RWP", __func__));
 		return;
 	}
 
-	while ((bus_read_4(res, GICD_CTLR) & GICD_CTLR_RWP) != 0) {
+	while ((bus_read_4(res, offset + GICD_CTLR) & GICD_CTLR_RWP) != 0) {
 		DELAY(1);
 		if (us_left-- == 0)
 			panic("GICD Register write pending for too long");
@@ -1377,8 +1384,8 @@ gic_v3_redist_alloc(struct gic_v3_softc *sc)
 static int
 gic_v3_redist_find(struct gic_v3_softc *sc)
 {
-	struct resource r_res;
-	bus_space_handle_t r_bsh;
+	struct resource *r_res;
+	bus_size_t offset;
 	uint64_t aff;
 	uint64_t typer;
 	uint32_t pidr2;
@@ -1399,10 +1406,9 @@ gic_v3_redist_find(struct gic_v3_softc *sc)
 	/* Iterate through Re-Distributor regions */
 	for (i = 0; i < sc->gic_redists.nregions; i++) {
 		/* Take a copy of the region's resource */
-		r_res = *sc->gic_redists.regions[i];
-		r_bsh = rman_get_bushandle(&r_res);
+		r_res = sc->gic_redists.regions[i];
 
-		pidr2 = bus_read_4(&r_res, GICR_PIDR2);
+		pidr2 = bus_read_4(r_res, GICR_PIDR2);
 		switch (GICR_PIDR2_ARCH(pidr2)) {
 		case GICR_PIDR2_ARCH_GICv3: /* fall through */
 		case GICR_PIDR2_ARCH_GICv4:
@@ -1413,13 +1419,15 @@ gic_v3_redist_find(struct gic_v3_softc *sc)
 			return (ENODEV);
 		}
 
+		offset = 0;
 		do {
-			typer = bus_read_8(&r_res, GICR_TYPER);
+			typer = bus_read_8(r_res, offset + GICR_TYPER);
 			if ((typer >> GICR_TYPER_AFF_SHIFT) == aff) {
 				KASSERT(sc->gic_redists.pcpu[cpuid] != NULL,
 				    ("Invalid pointer to per-CPU redistributor"));
 				/* Copy res contents to its final destination */
 				sc->gic_redists.pcpu[cpuid]->res = r_res;
+				sc->gic_redists.pcpu[cpuid]->offset = offset;
 				sc->gic_redists.pcpu[cpuid]->lpi_enabled = false;
 				if (bootverbose) {
 					device_printf(sc->dev,
@@ -1429,14 +1437,13 @@ gic_v3_redist_find(struct gic_v3_softc *sc)
 				return (0);
 			}
 
-			r_bsh += (GICR_RD_BASE_SIZE + GICR_SGI_BASE_SIZE);
+			offset += (GICR_RD_BASE_SIZE + GICR_SGI_BASE_SIZE);
 			if ((typer & GICR_TYPER_VLPIS) != 0) {
-				r_bsh +=
+				offset +=
 				    (GICR_VLPI_BASE_SIZE + GICR_RESERVED_SIZE);
 			}
-
-			rman_set_bushandle(&r_res, r_bsh);
-		} while ((typer & GICR_TYPER_LAST) == 0);
+		} while (offset < rman_get_size(r_res) &&
+		    (typer & GICR_TYPER_LAST) == 0);
 	}
 
 	device_printf(sc->dev, "No Re-Distributor found for CPU%u\n", cpuid);
diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h
index 9fa8b82e16bc..47e73c1ab3b7 100644
--- a/sys/arm64/arm64/gic_v3_var.h
+++ b/sys/arm64/arm64/gic_v3_var.h
@@ -40,8 +40,9 @@ DECLARE_CLASS(gic_v3_driver);
 struct gic_v3_irqsrc;
 
 struct redist_pcpu {
-	struct resource		res;		/* mem resource for redist */
+	struct resource		*res;		/* mem resource for redist */
 	vm_offset_t		pend_base;
+	bus_size_t		offset;
 	bool			lpi_enabled;	/* redist LPI configured? */
 };
 
@@ -137,8 +138,8 @@ void gic_r_write_8(device_t, bus_size_t, uint64_t var);
 	u_int cpu = PCPU_GET(cpuid);		\
 						\
 	bus_read_##len(				\
-	    &(sc)->gic_redists.pcpu[cpu]->res,	\
-	    (reg));				\
+	    (sc)->gic_redists.pcpu[cpu]->res,	\
+	    (sc)->gic_redists.pcpu[cpu]->offset + (reg)); \
 })
 
 #define	gic_r_write(sc, len, reg, val)		\
@@ -146,8 +147,9 @@ void gic_r_write_8(device_t, bus_size_t, uint64_t var);
 	u_int cpu = PCPU_GET(cpuid);		\
 						\
 	bus_write_##len(			\
-	    &(sc)->gic_redists.pcpu[cpu]->res,	\
-	    (reg), (val));			\
+	    (sc)->gic_redists.pcpu[cpu]->res,	\
+	    (sc)->gic_redists.pcpu[cpu]->offset + (reg), \
+	    (val));				\
 })
 
 #endif /* _GIC_V3_VAR_H_ */
diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
index 9c8f87e74f31..57351a7e76aa 100644
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -723,7 +723,8 @@ its_init_cpu(device_t dev, struct gicv3_its_softc *sc)
 
 	if ((gic_its_read_8(sc, GITS_TYPER) & GITS_TYPER_PTA) != 0) {
 		/* This ITS wants the redistributor physical address */
-		target = vtophys(rman_get_virtual(&rpcpu->res));
+		target = vtophys((vm_offset_t)rman_get_virtual(rpcpu->res) +
+		    rpcpu->offset);
 	} else {
 		/* This ITS wants the unique processor number */
 		target = GICR_TYPER_CPUNUM(gic_r_read_8(gicv3, GICR_TYPER)) <<