git: f8c90b704189 - main - gic_v3: Correctly handle GICC GIGR Base Address case

From: Jessica Clarke <jrtc27_at_FreeBSD.org>
Date: Mon, 09 Dec 2024 21:55:54 UTC
The branch main has been updated by jrtc27:

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

commit f8c90b704189c94275d22d7cc204d1d74e821d86
Author:     Jessica Clarke <jrtc27@FreeBSD.org>
AuthorDate: 2024-12-09 21:55:06 +0000
Commit:     Jessica Clarke <jrtc27@FreeBSD.org>
CommitDate: 2024-12-09 21:55:06 +0000

    gic_v3: Correctly handle GICC GIGR Base Address case
    
    When using the GICR Base Address field from each GICC structure instead
    of GICR structures, the field gives the address of a single
    redistributor page. However, that does not mean that they are not
    contiguous, and so GICR_TYPER.Last could be clear on them. Thus we must
    ignore GICR_TYPER.Last in this case and always treat each region as
    having a single page. Normally we'd do that as a result of checking
    against the rman's size (though that's a rather roundabout and iffy way
    of achieving it), but for whatever reason this is bigger on the Qualcomm
    Snapdragon X Elite (I assume the MADT reports GICv4 but TYPER doesn't
    report VLPIS and so there is a mismatch between the rman size and the
    stride used) and we end up walking off the region's mapping.
    
    Reviewed by:    andrew, phk
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D47560
---
 sys/arm64/arm64/gic_v3.c      | 2 +-
 sys/arm64/arm64/gic_v3_acpi.c | 1 +
 sys/arm64/arm64/gic_v3_var.h  | 6 ++++++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c
index 964a129111e2..201cdae6de09 100644
--- a/sys/arm64/arm64/gic_v3.c
+++ b/sys/arm64/arm64/gic_v3.c
@@ -1434,7 +1434,7 @@ gic_v3_redist_find(struct gic_v3_softc *sc)
 				    (GICR_VLPI_BASE_SIZE + GICR_RESERVED_SIZE);
 			}
 		} while (offset < rman_get_size(r_res) &&
-		    (typer & GICR_TYPER_LAST) == 0);
+		    !sc->gic_redists.single && (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_acpi.c b/sys/arm64/arm64/gic_v3_acpi.c
index 44c55cf5bbf2..7c3495fd442b 100644
--- a/sys/arm64/arm64/gic_v3_acpi.c
+++ b/sys/arm64/arm64/gic_v3_acpi.c
@@ -300,6 +300,7 @@ gic_v3_acpi_count_regions(device_t dev)
 		acpi_walk_subtables(madt + 1,
 		    (char *)madt + madt->Header.Length,
 		    madt_count_gicc_redistrib, sc);
+		sc->gic_redists.single = true;
 	}
 	acpi_unmap_table(madt);
 
diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h
index 1c5d354ee217..8bc0f456d91e 100644
--- a/sys/arm64/arm64/gic_v3_var.h
+++ b/sys/arm64/arm64/gic_v3_var.h
@@ -53,6 +53,12 @@ struct gic_redists {
 	struct resource **	regions;
 	/* Number of Re-Distributor regions */
 	u_int			nregions;
+	/*
+	 * Whether to treat each region as a single Re-Distributor page or a
+	 * series of contiguous pages (i.e. from each ACPI MADT GICC's GICR
+	 * Base Address field)
+	 */
+	bool			single;
 	/* Per-CPU Re-Distributor data */
 	struct redist_pcpu	*pcpu;
 };