aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2020-11-19 09:26:51 +0000
committerAndrew Turner <andrew@FreeBSD.org>2020-11-19 09:26:51 +0000
commit02a6de7789ee1fc14c879dd2e7cbaf6fbc4f5231 (patch)
tree31e3e0b580e597d7e4beabc78bc5b628bf238903
parentb8cb6285345527144af55cc590391880dfc205b4 (diff)
downloadsrc-02a6de7789ee1fc14c879dd2e7cbaf6fbc4f5231.tar.gz
src-02a6de7789ee1fc14c879dd2e7cbaf6fbc4f5231.zip
Fall back to use the GICR address from the generic interrupt struct
When there is no ACPI redistributor sub-table in the MADT we need to fall back to use the GICR base address from the GIC CPU interface structure. Handle this fallback when adding memory to the device and when counting the number of redistributors. PR: 251171 Reported by: Andrey Fesenko <f0andrey_gmail.com> Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D27247
Notes
Notes: svn path=/head/; revision=367841
-rw-r--r--sys/arm64/arm64/gic_v3_acpi.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/sys/arm64/arm64/gic_v3_acpi.c b/sys/arm64/arm64/gic_v3_acpi.c
index ad4dfd92eafa..e73e37f8e851 100644
--- a/sys/arm64/arm64/gic_v3_acpi.c
+++ b/sys/arm64/arm64/gic_v3_acpi.c
@@ -88,6 +88,7 @@ struct madt_table_data {
device_t dev;
ACPI_MADT_GENERIC_DISTRIBUTOR *dist;
int count;
+ bool rdist_use_gicc;
};
static void
@@ -120,12 +121,16 @@ static void
rdist_map(ACPI_SUBTABLE_HEADER *entry, void *arg)
{
ACPI_MADT_GENERIC_REDISTRIBUTOR *redist;
+ ACPI_MADT_GENERIC_INTERRUPT *intr;
struct madt_table_data *madt_data;
+ rman_res_t count;
madt_data = (struct madt_table_data *)arg;
switch(entry->Type) {
case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR:
+ if (madt_data->rdist_use_gicc)
+ break;
redist = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)entry;
madt_data->count++;
@@ -134,6 +139,23 @@ rdist_map(ACPI_SUBTABLE_HEADER *entry, void *arg)
redist->Length);
break;
+ case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
+ if (!madt_data->rdist_use_gicc)
+ break;
+
+ intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
+
+ madt_data->count++;
+ /*
+ * Map the two 64k redistributor frames.
+ */
+ count = GICR_RD_BASE_SIZE + GICR_SGI_BASE_SIZE;
+ if (madt_data->dist->Version == ACPI_MADT_GIC_VERSION_V4)
+ count += GICR_VLPI_BASE_SIZE + GICR_RESERVED_SIZE;
+ BUS_SET_RESOURCE(madt_data->parent, madt_data->dev,
+ SYS_RES_MEMORY, madt_data->count, intr->GicrBaseAddress,
+ count);
+
default:
break;
}
@@ -190,8 +212,18 @@ gic_v3_acpi_identify(driver_t *driver, device_t parent)
madt_data.dist->BaseAddress, 128 * 1024);
madt_data.dev = dev;
+ madt_data.rdist_use_gicc = false;
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
rdist_map, &madt_data);
+ if (madt_data.count == 0) {
+ /*
+ * No redistributors found, fall back to use the GICR
+ * address from the GICC sub-table.
+ */
+ madt_data.rdist_use_gicc = true;
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ rdist_map, &madt_data);
+ }
acpi_set_private(dev, (void *)(uintptr_t)madt_data.dist->Version);
@@ -224,6 +256,15 @@ madt_count_redistrib(ACPI_SUBTABLE_HEADER *entry, void *arg)
sc->gic_redists.nregions++;
}
+static void
+madt_count_gicc_redistrib(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ struct gic_v3_softc *sc = arg;
+
+ if (entry->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
+ sc->gic_redists.nregions++;
+}
+
static int
gic_v3_acpi_count_regions(device_t dev)
{
@@ -245,6 +286,12 @@ gic_v3_acpi_count_regions(device_t dev)
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
madt_count_redistrib, sc);
+ /* Fall back to use the distributor GICR base address */
+ if (sc->gic_redists.nregions == 0) {
+ acpi_walk_subtables(madt + 1,
+ (char *)madt + madt->Header.Length,
+ madt_count_gicc_redistrib, sc);
+ }
acpi_unmap_table(madt);
return (sc->gic_redists.nregions > 0 ? 0 : ENXIO);