git: e8aebac46453 - main - sys: arm64: acpica: Add support for GICv5 ITS & IWB nodes
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 09 Sep 2026 14:23:13 UTC
The branch main has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=e8aebac4645348b520e7d00c3eed59f1de228b87
commit e8aebac4645348b520e7d00c3eed59f1de228b87
Author: Sarah Walker <sarah.walker2@arm.com>
AuthorDate: 2026-08-04 12:33:46 +0000
Commit: Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-09-08 03:05:28 +0000
sys: arm64: acpica: Add support for GICv5 ITS & IWB nodes
Reviewed by: andrew
Sponsored by: Arm Ltd
Differential Revision: https://reviews.freebsd.org/D59168
---
sys/arm64/acpica/acpi_iort.c | 142 ++++++++++++++++++++++++++++++++++++++-----
sys/dev/acpica/acpivar.h | 2 +
2 files changed, 130 insertions(+), 14 deletions(-)
diff --git a/sys/arm64/acpica/acpi_iort.c b/sys/arm64/acpica/acpi_iort.c
index a180dc1a2a2c..eef2575fe432 100644
--- a/sys/arm64/acpica/acpi_iort.c
+++ b/sys/arm64/acpica/acpi_iort.c
@@ -33,6 +33,7 @@
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/sbuf.h>
#include <machine/intr.h>
@@ -82,6 +83,15 @@ struct iort_named_component
char DeviceName[32]; /* Path of namespace object */
};
+struct iort_iwb
+{
+ UINT64 BaseAddress;
+ /* Unique IWB identifier matching with the IWB GSI namespace. */
+ UINT16 IwbIndex;
+ /* Path of the IWB namespace object */
+ char DeviceName[32];
+};
+
/*
* 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
@@ -104,6 +114,7 @@ struct iort_node {
ACPI_IORT_SMMU smmu;
ACPI_IORT_SMMU_V3 smmu_v3;
struct iort_named_component named_comp;
+ struct iort_iwb iwb;
} data;
};
@@ -112,6 +123,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 TAILQ_HEAD(, iort_node) iwb_nodes = TAILQ_HEAD_INITIALIZER(iwb_nodes);
static int
iort_entry_get_id_mapping_index(struct iort_node *node)
@@ -325,6 +337,7 @@ iort_add_nodes(ACPI_IORT_NODE *node_entry, u_int node_offset)
ACPI_IORT_SMMU_V3 *smmu_v3;
ACPI_IORT_NAMED_COMPONENT *named_comp;
struct iort_node *node;
+ ACPI_IORT_IWB *iwb;
node = malloc(sizeof(*node), M_DEVBUF, M_WAITOK | M_ZERO);
node->type = node_entry->Type;
@@ -368,6 +381,19 @@ iort_add_nodes(ACPI_IORT_NODE *node_entry, u_int node_offset)
iort_copy_data(node, node_entry);
TAILQ_INSERT_TAIL(&named_nodes, node, next);
break;
+ case ACPI_IORT_NODE_IWB:
+ iwb = (ACPI_IORT_IWB *)node_entry->NodeData;
+ memcpy(&node->data.iwb, iwb, sizeof(*iwb));
+
+ /* Copy name of the node separately. */
+ strncpy(node->data.iwb.DeviceName,
+ iwb->DeviceName,
+ sizeof(node->data.iwb.DeviceName));
+ node->data.iwb.DeviceName[31] = 0;
+
+ iort_copy_data(node, node_entry);
+ TAILQ_INSERT_TAIL(&iwb_nodes, node, next);
+ break;
default:
printf("ACPI: IORT: Dropping unhandled type %u\n",
node_entry->Type);
@@ -429,6 +455,9 @@ iort_post_process_mappings(void)
TAILQ_FOREACH(node, &named_nodes, next)
for (i = 0; i < node->nentries; i++)
iort_resolve_node(&node->entries.mappings[i], TRUE);
+ TAILQ_FOREACH(node, &iwb_nodes, next)
+ for (i = 0; i < node->nentries; i++)
+ iort_resolve_node(&node->entries.mappings[i], FALSE);
}
/*
@@ -438,29 +467,50 @@ static void
madt_resolve_its_xref(ACPI_SUBTABLE_HEADER *entry, void *arg)
{
ACPI_MADT_GENERIC_TRANSLATOR *gict;
+ ACPI_MADT_GICv5_ITS *gicv5_its;
struct iort_node *its_node;
struct iort_its_entry *its_entry;
u_int xref;
int i, matches;
- if (entry->Type != ACPI_MADT_TYPE_GENERIC_TRANSLATOR)
- return;
+ switch (entry->Type) {
+ case ACPI_MADT_TYPE_GENERIC_TRANSLATOR:
+ gict = (ACPI_MADT_GENERIC_TRANSLATOR *)entry;
+ matches = 0;
+ xref = acpi_its_xref++;
+ TAILQ_FOREACH(its_node, &its_groups, next) {
+ its_entry = its_node->entries.its;
+ for (i = 0; i < its_node->nentries; i++, its_entry++) {
+ if (its_entry->its_id == gict->TranslationId) {
+ its_entry->xref = xref;
+ matches++;
+ }
+ }
+ }
+ if (matches == 0)
+ printf("ACPI: IORT: Unused ITS block, ID %u\n",
+ gict->TranslationId);
+ break;
- gict = (ACPI_MADT_GENERIC_TRANSLATOR *)entry;
- matches = 0;
- xref = acpi_its_xref++;
- TAILQ_FOREACH(its_node, &its_groups, next) {
- its_entry = its_node->entries.its;
- for (i = 0; i < its_node->nentries; i++, its_entry++) {
- if (its_entry->its_id == gict->TranslationId) {
- its_entry->xref = xref;
- matches++;
+ case ACPI_MADT_TYPE_GICV5_ITS:
+ gicv5_its = (ACPI_MADT_GICv5_ITS *)entry;
+ matches = 0;
+ xref = acpi_its_xref++;
+ TAILQ_FOREACH(its_node, &its_groups, next) {
+ its_entry = its_node->entries.its;
+ for (i = 0; i < its_node->nentries; i++, its_entry++) {
+ if (its_entry->its_id ==
+ gicv5_its->TranslatorId) {
+ its_entry->xref = xref;
+ matches++;
+ }
}
}
+ if (matches == 0)
+ printf("ACPI: IORT: Unused ITSv5 block, ID %u\n",
+ gicv5_its->TranslatorId);
+ break;
}
- if (matches == 0)
- printf("ACPI: IORT: Unused ITS block, ID %u\n",
- gict->TranslationId);
}
/*
@@ -690,3 +740,67 @@ acpi_iort_map_named_smmuv3(const char *devname, u_int rid, uint64_t *xref,
return (0);
}
+
+static struct iort_node *
+acpi_iort_lookup_iwb_node(device_t bus, device_t child)
+{
+ struct iort_node *node;
+ struct sbuf *sb = sbuf_new_auto();
+
+ if (acpi_get_acpi_device_path(bus, child, BUS_LOCATOR_ACPI, sb))
+ return (NULL);
+
+ sbuf_finish(sb);
+
+ TAILQ_FOREACH(node, &iwb_nodes, next) {
+ if (!strcmp(sbuf_data(sb), node->data.iwb.DeviceName)) {
+ sbuf_delete(sb);
+ return (node);
+ }
+ }
+
+ sbuf_delete(sb);
+ return (NULL);
+}
+
+int
+acpi_iort_lookup_its_from_iwb(device_t dev, int *its_id)
+{
+ struct iort_node *node;
+ struct iort_node *out_node;
+ device_t bus = device_get_parent(dev);
+ int i;
+
+ node = acpi_iort_lookup_iwb_node(bus, dev);
+ if (!node)
+ return (ENODEV);
+
+ for (i = 0; i < node->nentries; i++) {
+ out_node = node->entries.mappings[i].out_node;
+ if (out_node->type == ACPI_IORT_NODE_ITS_GROUP) {
+ *its_id = out_node->entries.its[0].its_id;
+ return (0);
+ }
+ }
+
+ return (ENODEV);
+}
+
+device_t
+acpi_iort_get_iwb_dev(int iwb_id)
+{
+ struct iort_node *node;
+ ACPI_HANDLE iwb_handle;
+
+ TAILQ_FOREACH(node, &iwb_nodes, next) {
+ if (node->data.iwb.IwbIndex == iwb_id) {
+ if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT,
+ node->data.iwb.DeviceName, &iwb_handle)))
+ panic("Can't get IWB ACPI handle\n");
+
+ return (acpi_get_device(iwb_handle));
+ }
+ }
+
+ return (NULL);
+}
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 028b39637a45..05d581b77fb9 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -640,6 +640,8 @@ 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,
uint64_t *xref, u_int *devid);
+int acpi_iort_lookup_its_from_iwb(device_t dev, int *its_id);
+device_t acpi_iort_get_iwb_dev(int iwb_id);
#endif
#endif /* _KERNEL */
#endif /* !_ACPIVAR_H_ */