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>
