[Differential] D31267: Parse named nodes from IORT ACPI on arm64

"dsl_mcusim.org (Dmitry Salychev)" <[email protected]>
Newsgroups gmane.os.freebsd.devel.arm
Message-ID <[email protected]>
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
D31267.92616.patch (text/x-patch, 5.5 KB)
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);
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.