Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Jul 2021 09:05:43 +0000
From:      "dsl_mcusim.org (Dmitry Salychev)" <phabric-noreply@FreeBSD.org>
To:        freebsd-arm@freebsd.org
Subject:   [Differential] D31267: Parse named nodes from IORT ACPI on arm64
Message-ID:  <479fff3d782baa3bf06f082e57c2d721@localhost.localdomain>
In-Reply-To: <differential-rev-PHID-DREV-oq76npafhgjmziyg7wtl-req@reviews.freebsd.org>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
dsl_mcusim.org created this revision.
dsl_mcusim.org added a reviewer: freebsd-arm-list.
Herald added subscribers: emaste, andrew.
Herald added a reviewer: manu.
dsl_mcusim.org requested review of this revision.

REVISION SUMMARY
  During my work on a driver for DPAA2 (NXP's network feature available in several of their SoCs) firmware bus, I discovered that it isn't possible to map a named component mentioned in IORT to its SMMU or ITS node in order to setup interrupts. It's possible to find a named node by its names (as a substring) and a resource ID (isolation context ID in case of DPAA2) similar to PCI nodes with this patch.

TEST PLAN
  1. Clone my fork with DPAA2 work-in-progress from https://github.com/mcusim/freebsd-src.
  2. Build and boot to the kernel on SolidRun's HoneyComb board.
  3. Build and load KLD from sys/modules/dpaa2.
  4. Find "dpaa2_rc0: MSI allocated: irq=..." in dmesg

REVISION DETAIL
  https://reviews.freebsd.org/D31267

AFFECTED FILES
  sys/arm64/acpica/acpi_iort.c
  sys/dev/acpica/acpivar.h

EMAIL PREFERENCES
  https://reviews.freebsd.org/settings/panel/emailpreferences/

To: dsl_mcusim.org, freebsd-arm-list, manu
Cc: andrew, freebsd-arm-list, emaste

[-- Attachment #2 --]
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -578,6 +578,10 @@
 int	acpi_iort_map_pci_msi(u_int seg, u_int rid, u_int *xref, u_int *devid);
 int	acpi_iort_map_pci_smmuv3(u_int seg, u_int rid, u_int *xref, u_int *devid);
 int	acpi_iort_its_lookup(u_int its_id, u_int *xref, int *pxm);
+int	acpi_iort_map_named_msi(const char *devname, u_int rid, u_int *xref,
+	    u_int *devid);
+int	acpi_iort_map_named_smmuv3(const char *devname, u_int rid, u_int *xref,
+	    u_int *devid);
 #endif
 #endif /* _KERNEL */
 #endif /* !_ACPIVAR_H_ */
diff --git a/sys/arm64/acpica/acpi_iort.c b/sys/arm64/acpica/acpi_iort.c
--- a/sys/arm64/acpica/acpi_iort.c
+++ b/sys/arm64/acpica/acpi_iort.c
@@ -77,6 +77,14 @@
 	int			pxm;
 };
 
+struct iort_named_component
+{
+	UINT32                  NodeFlags;
+	UINT64                  MemoryProperties;
+	UINT8                   MemoryAddressLimit;
+	char                    DeviceName[32]; /* Path of namespace object */
+};
+
 /*
  * IORT node. Each node has some device specific data depending on the
  * type of the node. The node can also have a set of mappings, OR in
@@ -91,9 +99,10 @@
 	u_int			usecount;	/* for bookkeeping */
 	u_int			revision;	/* node revision */
 	union {
-		ACPI_IORT_ROOT_COMPLEX	pci_rc;		/* PCI root complex */
-		ACPI_IORT_SMMU		smmu;
-		ACPI_IORT_SMMU_V3	smmu_v3;
+		ACPI_IORT_ROOT_COMPLEX		pci_rc;	/* PCI root complex */
+		ACPI_IORT_SMMU			smmu;
+		ACPI_IORT_SMMU_V3		smmu_v3;
+		struct iort_named_component	named_comp;
 	} data;
 	union {
 		struct iort_map_entry	*mappings;	/* node mappings  */
@@ -105,6 +114,7 @@
 static TAILQ_HEAD(, iort_node) pci_nodes = TAILQ_HEAD_INITIALIZER(pci_nodes);
 static TAILQ_HEAD(, iort_node) smmu_nodes = TAILQ_HEAD_INITIALIZER(smmu_nodes);
 static TAILQ_HEAD(, iort_node) its_groups = TAILQ_HEAD_INITIALIZER(its_groups);
+static TAILQ_HEAD(, iort_node) named_nodes = TAILQ_HEAD_INITIALIZER(named_nodes);
 
 static int
 iort_entry_get_id_mapping_index(struct iort_node *node)
@@ -202,6 +212,42 @@
 	return (out_node);
 }
 
+/*
+ * Map a named component node to a SMMU node or an ITS node, based on outtype.
+ */
+static struct iort_node *
+iort_named_comp_map(const char *devname, u_int rid, u_int outtype, u_int *outid)
+{
+	struct iort_node *node, *out_node;
+	u_int nxtid;
+
+	out_node = NULL;
+	TAILQ_FOREACH(node, &named_nodes, next) {
+		if (strstr(node->data.named_comp.DeviceName, devname) == NULL)
+			continue;
+		out_node = iort_entry_lookup(node, rid, &nxtid);
+		if (out_node != NULL)
+			break;
+	}
+
+	/* Could not find a named node with this devname or rid. */
+	if (out_node == NULL)
+		return (NULL);
+
+	/* Node can be SMMU or ITS. If SMMU, we need another lookup. */
+	if (outtype == ACPI_IORT_NODE_ITS_GROUP &&
+	    (out_node->type == ACPI_IORT_NODE_SMMU_V3 ||
+	    out_node->type == ACPI_IORT_NODE_SMMU)) {
+		out_node = iort_entry_lookup(out_node, nxtid, &nxtid);
+		if (out_node == NULL)
+			return (NULL);
+	}
+
+	KASSERT(out_node->type == outtype, ("mapping fail"));
+	*outid = nxtid;
+	return (out_node);
+}
+
 #ifdef notyet
 /*
  * Not implemented, map a PCIe device to the SMMU it is associated with.
@@ -279,6 +325,7 @@
 	ACPI_IORT_ROOT_COMPLEX *pci_rc;
 	ACPI_IORT_SMMU *smmu;
 	ACPI_IORT_SMMU_V3 *smmu_v3;
+	ACPI_IORT_NAMED_COMPONENT *named_comp;
 	struct iort_node *node;
 
 	node = malloc(sizeof(*node), M_DEVBUF, M_WAITOK | M_ZERO);
@@ -310,6 +357,19 @@
 		iort_copy_its(node, node_entry);
 		TAILQ_INSERT_TAIL(&its_groups, node, next);
 		break;
+	case ACPI_IORT_NODE_NAMED_COMPONENT:
+		named_comp = (ACPI_IORT_NAMED_COMPONENT *)node_entry->NodeData;
+		memcpy(&node->data.named_comp, named_comp, sizeof(*named_comp));
+
+		/* Copy name of the node separately. */
+		strncpy(node->data.named_comp.DeviceName,
+		    named_comp->DeviceName,
+		    sizeof(node->data.named_comp.DeviceName));
+		node->data.named_comp.DeviceName[31] = 0;
+
+		iort_copy_data(node, node_entry);
+		TAILQ_INSERT_TAIL(&named_nodes, node, next);
+		break;
 	default:
 		printf("ACPI: IORT: Dropping unhandled type %u\n",
 		    node_entry->Type);
@@ -368,7 +428,9 @@
 	TAILQ_FOREACH(node, &smmu_nodes, next)
 		for (i = 0; i < node->nentries; i++)
 			iort_resolve_node(&node->entries.mappings[i], FALSE);
-	/* TODO: named nodes */
+	TAILQ_FOREACH(node, &named_nodes, next)
+		for (i = 0; i < node->nentries; i++)
+			iort_resolve_node(&node->entries.mappings[i], TRUE);
 }
 
 /*
@@ -587,3 +649,46 @@
 
 	return (0);
 }
+
+/*
+ * Finds mapping for a named node given name and resource ID and returns the
+ * XREF for MSI interrupt setup and the device ID to use for the interrupt setup.
+ */
+int
+acpi_iort_map_named_msi(const char *devname, u_int rid, u_int *xref,
+    u_int *devid)
+{
+	struct iort_node *node;
+
+	node = iort_named_comp_map(devname, rid, ACPI_IORT_NODE_ITS_GROUP,
+	    devid);
+	if (node == NULL)
+		return (ENOENT);
+
+	/* This should be an ITS node */
+	KASSERT(node->type == ACPI_IORT_NODE_ITS_GROUP, ("bad group"));
+
+	/* Return first node, we don't handle more than that now. */
+	*xref = node->entries.its[0].xref;
+	return (0);
+}
+
+int
+acpi_iort_map_named_smmuv3(const char *devname, u_int rid, u_int *xref,
+    u_int *devid)
+{
+	ACPI_IORT_SMMU_V3 *smmu;
+	struct iort_node *node;
+
+	node = iort_named_comp_map(devname, rid, ACPI_IORT_NODE_SMMU_V3, devid);
+	if (node == NULL)
+		return (ENOENT);
+
+	/* This should be an SMMU node. */
+	KASSERT(node->type == ACPI_IORT_NODE_SMMU_V3, ("bad node"));
+
+	smmu = (ACPI_IORT_SMMU_V3 *)&node->data.smmu_v3;
+	*xref = smmu->BaseAddress;
+
+	return (0);
+}

home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?479fff3d782baa3bf06f082e57c2d721>