summaryrefslogtreecommitdiff
path: root/sys/arch/arm64
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2023-09-12 08:32:59 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2023-09-12 08:32:59 +0000
commit578c533b438ae0a2427c3abcafce65d1e0328365 (patch)
treee597bb303b59f64b5f68c46e216c4ea7dc83f96d /sys/arch/arm64
parentc591c3423b368e62af9c9a6b2e4b433e5a31e377 (diff)
Use IORT ITS nodes to find the right ITS instance to use when establishing
interrupts. This makes MSI/MSI-X work on platforms like the Ampere Altra which have an ITS instance for each PCI domain. also tested by cheloha@ ok kettenis@ patrick@
Diffstat (limited to 'sys/arch/arm64')
-rw-r--r--sys/arch/arm64/dev/acpipci.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/sys/arch/arm64/dev/acpipci.c b/sys/arch/arm64/dev/acpipci.c
index 76060ab8a98..937b2c53e0a 100644
--- a/sys/arch/arm64/dev/acpipci.c
+++ b/sys/arch/arm64/dev/acpipci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpipci.c,v 1.39 2023/04/18 12:39:32 kettenis Exp $ */
+/* $OpenBSD: acpipci.c,v 1.40 2023/09/12 08:32:58 jmatthew Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis
*
@@ -124,7 +124,10 @@ void *acpipci_intr_establish(void *, pci_intr_handle_t, int,
struct cpu_info *, int (*)(void *), void *, char *);
void acpipci_intr_disestablish(void *, void *);
-uint32_t acpipci_iort_map_msi(pci_chipset_tag_t, pcitag_t);
+uint32_t acpipci_iort_map_msi(pci_chipset_tag_t, pcitag_t,
+ struct interrupt_controller **);
+
+extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
int
acpipci_match(struct device *parent, void *match, void *aux)
@@ -190,7 +193,6 @@ acpipci_attach(struct device *parent, struct device *self, void *aux)
sc->sc_bus_memt._space_map = acpipci_bs_map;
sc->sc_bus_memt._space_mmap = acpipci_bs_mmap;
- extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
if (ic->ic_establish_msi)
break;
@@ -632,7 +634,7 @@ acpipci_intr_establish(void *v, pci_intr_handle_t ih, int level,
KASSERT(ic);
/* Map Requester ID through IORT to get sideband data. */
- data = acpipci_iort_map_msi(ih.ih_pc, ih.ih_tag);
+ data = acpipci_iort_map_msi(ih.ih_pc, ih.ih_tag, &ic);
cookie = ic->ic_establish_msi(ic->ic_cookie, &addr,
&data, level, ci, func, arg, name);
if (cookie == NULL)
@@ -797,11 +799,12 @@ pci_lookup_segment(int segment)
* IORT support.
*/
-uint32_t acpipci_iort_map(struct acpi_iort *, uint32_t, uint32_t);
+uint32_t acpipci_iort_map(struct acpi_iort *, uint32_t, uint32_t,
+ struct interrupt_controller **);
uint32_t
acpipci_iort_map_node(struct acpi_iort *iort,
- struct acpi_iort_node *node, uint32_t id)
+ struct acpi_iort_node *node, uint32_t id, struct interrupt_controller **ic)
{
struct acpi_iort_mapping *map =
(struct acpi_iort_mapping *)((char *)node + node->mapping_offset);
@@ -812,14 +815,14 @@ acpipci_iort_map_node(struct acpi_iort *iort,
if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) {
id = map[i].output_base;
- return acpipci_iort_map(iort, offset, id);
+ return acpipci_iort_map(iort, offset, id, ic);
}
/* Mapping encodes number of IDs in the range minus one. */
if (map[i].input_base <= id &&
id <= map[i].input_base + map[i].number_of_ids) {
id = map[i].output_base + (id - map[i].input_base);
- return acpipci_iort_map(iort, offset, id);
+ return acpipci_iort_map(iort, offset, id, ic);
}
}
@@ -827,24 +830,39 @@ acpipci_iort_map_node(struct acpi_iort *iort,
}
uint32_t
-acpipci_iort_map(struct acpi_iort *iort, uint32_t offset, uint32_t id)
+acpipci_iort_map(struct acpi_iort *iort, uint32_t offset, uint32_t id,
+ struct interrupt_controller **ic)
{
struct acpi_iort_node *node =
(struct acpi_iort_node *)((char *)iort + offset);
+ struct interrupt_controller *icl;
+ struct acpi_iort_its_node *itsn;
+ int i;
switch (node->type) {
case ACPI_IORT_ITS:
+ itsn = (struct acpi_iort_its_node *)&node[1];
+ LIST_FOREACH(icl, &interrupt_controllers, ic_list) {
+ for (i = 0; i < itsn->number_of_itss; i++) {
+ if (icl->ic_gic_its_id == itsn->its_ids[i]) {
+ *ic = icl;
+ break;
+ }
+ }
+ }
+
return id;
case ACPI_IORT_SMMU:
case ACPI_IORT_SMMU_V3:
- return acpipci_iort_map_node(iort, node, id);
+ return acpipci_iort_map_node(iort, node, id, ic);
}
return id;
}
uint32_t
-acpipci_iort_map_msi(pci_chipset_tag_t pc, pcitag_t tag)
+acpipci_iort_map_msi(pci_chipset_tag_t pc, pcitag_t tag,
+ struct interrupt_controller **ic)
{
struct acpipci_softc *sc = pc->pc_intr_v;
struct acpi_table_header *hdr;
@@ -877,7 +895,8 @@ acpipci_iort_map_msi(pci_chipset_tag_t pc, pcitag_t tag)
case ACPI_IORT_ROOT_COMPLEX:
rc = (struct acpi_iort_rc_node *)&node[1];
if (rc->segment == sc->sc_seg)
- return acpipci_iort_map_node(iort, node, rid);
+ return acpipci_iort_map_node(iort, node, rid,
+ ic);
break;
}
offset += node->length;