diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2018-08-11 22:47:28 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2018-08-11 22:47:28 +0000 |
commit | 28bc5f77679a3eed3073ffeb6a21902f3aea4c0b (patch) | |
tree | f24ccdfa2ec2c92c9c06b5ebac31239af1935300 /sys | |
parent | f188684608b65623a4abe31556ff65d9a08a124f (diff) |
Make legacy interrupts work in more cases.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/arm64/dev/acpipci.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/sys/arch/arm64/dev/acpipci.c b/sys/arch/arm64/dev/acpipci.c index 954aaf8c9ab..5b067a254e8 100644 --- a/sys/arch/arm64/dev/acpipci.c +++ b/sys/arch/arm64/dev/acpipci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpipci.c,v 1.5 2018/08/11 20:46:48 kettenis Exp $ */ +/* $OpenBSD: acpipci.c,v 1.6 2018/08/11 22:47:27 kettenis Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -344,24 +344,51 @@ struct acpipci_intr_handle { }; int +acpipci_intr_swizzle(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + struct acpipci_intr_handle *ih; + int dev, swizpin; + + if (pa->pa_bridgetag == NULL) + return -1; + + pci_decompose_tag(pa->pa_pc, pa->pa_tag, NULL, &dev, NULL); + swizpin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); + if ((void *)pa->pa_bridgeih[swizpin - 1] == NULL) + return -1; + + ih = malloc(sizeof(struct acpipci_intr_handle), M_DEVBUF, M_WAITOK); + memcpy(ih, (void *)pa->pa_bridgeih[swizpin - 1], + sizeof(struct acpipci_intr_handle)); + *ihp = (pci_intr_handle_t)ih; + + return 0; +} + +int acpipci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { struct acpipci_softc *sc = pa->pa_pc->pc_intr_v; - struct aml_node *node; + struct aml_node *node = sc->sc_node; struct aml_value res; uint64_t addr, pin, source, index; struct acpipci_intr_handle *ih; int i; - if (pa->pa_bridgetag == NULL) - return -1; - - node = acpi_find_pci(pa->pa_pc, *pa->pa_bridgetag); - if (node == NULL) - return -1; + /* + * If we're behind a bridge, we need to look for a _PRT for + * it. If we don't find a _PRT, we need to swizzle. If we're + * not behind a bridge we need to look for a _PRT on the host + * bridge node itself. + */ + if (pa->pa_bridgetag) { + node = acpi_find_pci(pa->pa_pc, *pa->pa_bridgetag); + if (node == NULL) + return acpipci_intr_swizzle(pa, ihp); + } if (aml_evalname(sc->sc_acpi, node, "_PRT", 0, NULL, &res)) - return -1; + return acpipci_intr_swizzle(pa, ihp); if (res.type != AML_OBJTYPE_PACKAGE) return -1; |