svn commit: r367841 - head/sys/arm64/arm64

Andrew Turner andrew at FreeBSD.org
Thu Nov 19 09:26:52 UTC 2020


Author: andrew
Date: Thu Nov 19 09:26:51 2020
New Revision: 367841
URL: https://svnweb.freebsd.org/changeset/base/367841

Log:
  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

Modified:
  head/sys/arm64/arm64/gic_v3_acpi.c

Modified: head/sys/arm64/arm64/gic_v3_acpi.c
==============================================================================
--- head/sys/arm64/arm64/gic_v3_acpi.c	Thu Nov 19 09:17:41 2020	(r367840)
+++ head/sys/arm64/arm64/gic_v3_acpi.c	Thu Nov 19 09:26:51 2020	(r367841)
@@ -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
 		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);


More information about the svn-src-head mailing list