git: ae16cbfdd2a1 - main - gicv3: Use an offset to find the redist registers
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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)) <<