[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);
+}