Make legacy interrupts work in more cases.
authorkettenis <kettenis@openbsd.org>
Sat, 11 Aug 2018 22:47:27 +0000 (22:47 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 11 Aug 2018 22:47:27 +0000 (22:47 +0000)
sys/arch/arm64/dev/acpipci.c

index 954aaf8..5b067a2 100644 (file)
@@ -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
  *
@@ -343,25 +343,52 @@ struct acpipci_intr_handle {
        int                     ih_msi;
 };
 
+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;