Module Name: src Committed By: jmcneill Date: Sun Sep 9 13:40:28 UTC 2018
Modified Files: src/sys/arch/arm/fdt: pcihost_fdt.c Log Message: Take interrupt-map-mask into consideration when mapping PCI interrupts. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/fdt/pcihost_fdt.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/fdt/pcihost_fdt.c diff -u src/sys/arch/arm/fdt/pcihost_fdt.c:1.1 src/sys/arch/arm/fdt/pcihost_fdt.c:1.2 --- src/sys/arch/arm/fdt/pcihost_fdt.c:1.1 Sat Sep 8 00:40:57 2018 +++ src/sys/arch/arm/fdt/pcihost_fdt.c Sun Sep 9 13:40:28 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: pcihost_fdt.c,v 1.1 2018/09/08 00:40:57 jmcneill Exp $ */ +/* $NetBSD: pcihost_fdt.c,v 1.2 2018/09/09 13:40:28 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.1 2018/09/08 00:40:57 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.2 2018/09/09 13:40:28 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -50,7 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: pcihost_fdt. #include <dev/fdt/fdtvar.h> -#define IH_PIN_MASK 0x0000000f +#define IH_INDEX_MASK 0x0000ffff #define IH_MPSAFE 0x80000000 #define PCIHOST_DEFAULT_BUS_MIN 0 @@ -402,25 +402,69 @@ pcihost_conf_interrupt(void *v, int bus, static int pcihost_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih) { + struct pcihost_softc *sc = pa->pa_pc->pc_intr_v; + u_int addr_cells, interrupt_cells; + const u_int *imap, *imask; + int imaplen, imasklen; + u_int match[4]; + int index; + if (pa->pa_intrpin == 0) return EINVAL; - *ih = pa->pa_intrpin; - return 0; + + imap = fdtbus_get_prop(sc->sc_phandle, "interrupt-map", &imaplen); + imask = fdtbus_get_prop(sc->sc_phandle, "interrupt-map-mask", &imasklen); + if (imap == NULL || imask == NULL || imasklen != 16) + return EINVAL; + + /* Convert attach args to specifier */ + match[0] = htobe32( + __SHIFTIN(pa->pa_bus, PHYS_HI_BUS) | + __SHIFTIN(pa->pa_device, PHYS_HI_DEVICE) | + __SHIFTIN(pa->pa_function, PHYS_HI_FUNCTION) + ) & imask[0]; + match[1] = htobe32(0) & imask[1]; + match[2] = htobe32(0) & imask[2]; + match[3] = htobe32(pa->pa_intrpin) & imask[3]; + + index = 0; + while (imaplen >= 20) { + const int map_ihandle = fdtbus_get_phandle_from_native(be32toh(imap[4])); + if (of_getprop_uint32(map_ihandle, "#address-cells", &addr_cells)) + addr_cells = 2; + if (of_getprop_uint32(map_ihandle, "#interrupt-cells", &interrupt_cells)) + interrupt_cells = 0; + if (imaplen < (addr_cells + interrupt_cells) * 4) + return ENXIO; + + if ((imap[0] & imask[0]) == match[0] && + (imap[1] & imask[1]) == match[1] && + (imap[2] & imask[2]) == match[2] && + (imap[3] & imask[3]) == match[3]) { + *ih = index; + return 0; + } + + imap += (5 + addr_cells + interrupt_cells); + imaplen -= (5 + addr_cells + interrupt_cells) * 4; + index++; + } + + return EINVAL; } static const u_int * -pcihost_find_intr(struct pcihost_softc *sc, int pin, int *pihandle) +pcihost_find_intr(struct pcihost_softc *sc, pci_intr_handle_t ih, int *pihandle) { u_int addr_cells, interrupt_cells; + int imaplen, index; const u_int *imap; - int imaplen; imap = fdtbus_get_prop(sc->sc_phandle, "interrupt-map", &imaplen); - if (imap == NULL) - return NULL; + KASSERT(imap != NULL); + index = 0; while (imaplen >= 20) { - const int map_pin = be32toh(imap[3]); const int map_ihandle = fdtbus_get_phandle_from_native(be32toh(imap[4])); if (of_getprop_uint32(map_ihandle, "#address-cells", &addr_cells)) addr_cells = 2; @@ -429,13 +473,14 @@ pcihost_find_intr(struct pcihost_softc * if (imaplen < (addr_cells + interrupt_cells) * 4) return NULL; - if (map_pin == pin) { + if (index == ih) { *pihandle = map_ihandle; return imap + 5 + addr_cells; } - imap += (addr_cells + interrupt_cells); - imaplen -= (addr_cells + interrupt_cells) * 4; + imap += (5 + addr_cells + interrupt_cells); + imaplen -= (5 + addr_cells + interrupt_cells) * 4; + index++; } return NULL; @@ -445,14 +490,10 @@ static const char * pcihost_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len) { struct pcihost_softc *sc = v; - u_int pin = ih & IH_PIN_MASK; const u_int *specifier; int ihandle; - if (pin == PCI_INTERRUPT_PIN_NONE || pin > PCI_INTERRUPT_PIN_MAX) - return NULL; - - specifier = pcihost_find_intr(sc, pin, &ihandle); + specifier = pcihost_find_intr(sc, ih & IH_INDEX_MASK, &ihandle); if (specifier == NULL) return NULL; @@ -488,15 +529,11 @@ pcihost_intr_establish(void *v, pci_intr int (*callback)(void *), void *arg) { struct pcihost_softc *sc = v; - u_int pin = ih & IH_PIN_MASK; const int flags = (ih & IH_MPSAFE) ? FDT_INTR_MPSAFE : 0; const u_int *specifier; int ihandle; - if (pin == PCI_INTERRUPT_PIN_NONE || pin > PCI_INTERRUPT_PIN_MAX) - return NULL; - - specifier = pcihost_find_intr(sc, pin, &ihandle); + specifier = pcihost_find_intr(sc, ih & IH_INDEX_MASK, &ihandle); if (specifier == NULL) return NULL;