diff options
-rw-r--r-- | sys/arch/arm64/arm64/acpi_machdep.c | 6 | ||||
-rw-r--r-- | sys/arch/arm64/dev/acpiiort.c | 75 | ||||
-rw-r--r-- | sys/arch/arm64/dev/acpiiort.h | 3 |
3 files changed, 80 insertions, 4 deletions
diff --git a/sys/arch/arm64/arm64/acpi_machdep.c b/sys/arch/arm64/arm64/acpi_machdep.c index 5d78f6d9638..721f45e3210 100644 --- a/sys/arch/arm64/arm64/acpi_machdep.c +++ b/sys/arch/arm64/arm64/acpi_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_machdep.c,v 1.12 2021/03/15 22:44:57 patrick Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.13 2021/03/15 22:56:48 patrick Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -31,6 +31,8 @@ #include <dev/acpi/acpivar.h> #include <dev/acpi/dsdt.h> +#include <arm64/dev/acpiiort.h> + int lid_action; int pwr_action = 1; @@ -220,5 +222,5 @@ acpi_resume_mp(void) bus_dma_tag_t acpi_iommu_device_map(struct aml_node *node, bus_dma_tag_t dmat) { - return dmat; + return acpiiort_device_map(node, dmat); } diff --git a/sys/arch/arm64/dev/acpiiort.c b/sys/arch/arm64/dev/acpiiort.c index 710d8fdb6ec..8569b4932d7 100644 --- a/sys/arch/arm64/dev/acpiiort.c +++ b/sys/arch/arm64/dev/acpiiort.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiiort.c,v 1.2 2021/03/15 22:48:57 patrick Exp $ */ +/* $OpenBSD: acpiiort.c,v 1.3 2021/03/15 22:56:48 patrick Exp $ */ /* * Copyright (c) 2021 Patrick Wildt <patrick@blueri.se> * @@ -21,6 +21,7 @@ #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> +#include <dev/acpi/dsdt.h> #include <arm64/dev/acpiiort.h> @@ -101,3 +102,75 @@ acpiiort_smmu_map(struct acpi_iort_node *node, uint32_t rid, return dmat; } + +bus_dma_tag_t +acpiiort_device_map(struct aml_node *root, bus_dma_tag_t dmat) +{ + struct acpi_table_header *hdr; + struct acpi_iort *iort = NULL; + struct acpi_iort_node *node; + struct acpi_iort_mapping *map; + struct acpi_iort_nc_node *nc; + struct acpi_q *entry; + const char *name; + uint32_t rid, offset; + int i; + + name = aml_nodename(root); + + /* Look for IORT table. */ + SIMPLEQ_FOREACH(entry, &acpi_softc->sc_tables, q_next) { + hdr = entry->q_table; + if (strncmp(hdr->signature, IORT_SIG, + sizeof(hdr->signature)) == 0) { + iort = entry->q_table; + break; + } + } + if (iort == NULL) + return dmat; + + /* Find our named component. */ + offset = iort->offset; + for (i = 0; i < iort->number_of_nodes; i++) { + node = (struct acpi_iort_node *)((char *)iort + offset); + if (node->type == ACPI_IORT_NAMED_COMPONENT) { + nc = (struct acpi_iort_nc_node *)&node[1]; + if (strcmp(nc->device_object_name, name) == 0) + break; + } + offset += node->length; + } + + /* No NC found? Weird. */ + if (i >= iort->number_of_nodes) + return dmat; + + /* Find our output base towards SMMU. */ + map = (struct acpi_iort_mapping *)((char *)node + node->mapping_offset); + for (i = 0; i < node->number_of_mappings; i++) { + offset = map[i].output_reference; + + if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) { + rid = map[i].output_base; + break; + } + + /* Mapping encodes number of IDs in the range minus one. */ + if (map[i].input_base <= rid && + rid <= map[i].input_base + map[i].number_of_ids) { + rid = map[i].output_base + (rid - map[i].input_base); + break; + } + } + + /* No mapping found? Even weirder. */ + if (i >= node->number_of_mappings) + return dmat; + + node = (struct acpi_iort_node *)((char *)iort + offset); + if (node->type == ACPI_IORT_SMMU) + return acpiiort_smmu_map(node, rid, dmat); + + return dmat; +} diff --git a/sys/arch/arm64/dev/acpiiort.h b/sys/arch/arm64/dev/acpiiort.h index fd0c991526f..5aaaa02c17b 100644 --- a/sys/arch/arm64/dev/acpiiort.h +++ b/sys/arch/arm64/dev/acpiiort.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiiort.h,v 1.2 2021/03/15 22:48:57 patrick Exp $ */ +/* $OpenBSD: acpiiort.h,v 1.3 2021/03/15 22:56:48 patrick Exp $ */ /* * Copyright (c) 2021 Patrick Wildt <patrick@blueri.se> * @@ -32,3 +32,4 @@ struct acpiiort_smmu { void acpiiort_smmu_register(struct acpiiort_smmu *); bus_dma_tag_t acpiiort_smmu_map(struct acpi_iort_node *, uint32_t, bus_dma_tag_t); +bus_dma_tag_t acpiiort_device_map(struct aml_node *, bus_dma_tag_t); |