diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 2a56bb7fce98a..ddabafdf017ae 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: pci.c,v 1.155 2019/10/14 00:20:09 jmcneill Exp $ */ +/* $NetBSD: pci.c,v 1.156 2019/10/15 13:27:11 jmcneill Exp $ */ /* * Copyright (c) 1995, 1996, 1997, 1998 @@ -36,7 +36,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.155 2019/10/14 00:20:09 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.156 2019/10/15 13:27:11 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_pci.h" @@ -695,17 +695,26 @@ pci_enumerate_bus(struct pci_softc *sc, const int *locators, device_t bridgedev; bool arien = false; + bool downstream_port = false; - /* Check PCIe ARI */ + /* Check PCIe ARI and port type */ bridgedev = device_parent(sc->sc_dev); if (device_is_a(bridgedev, "ppb")) { struct ppb_softc *ppbsc = device_private(bridgedev); pci_chipset_tag_t ppbpc = ppbsc->sc_pc; pcitag_t ppbtag = ppbsc->sc_tag; - pcireg_t pciecap, reg; + pcireg_t pciecap, capreg, reg; if (pci_get_capability(ppbpc, ppbtag, PCI_CAP_PCIEXPRESS, - &pciecap, NULL) != 0) { + &pciecap, &capreg) != 0) { + switch (PCIE_XCAP_TYPE(capreg)) { + case PCIE_XCAP_TYPE_ROOT: + case PCIE_XCAP_TYPE_DOWN: + case PCIE_XCAP_TYPE_PCI2PCIE: + downstream_port = true; + break; + } + reg = pci_conf_read(ppbpc, ppbtag, pciecap + PCIE_DCSR2); if ((reg & PCIE_DCSR2_ARI_FWD) != 0) @@ -714,6 +723,11 @@ pci_enumerate_bus(struct pci_softc *sc, const int *locators, } n = pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs, __arraycount(devs)); + if (downstream_port) { + /* PCIe downstream ports only have a single child device */ + n = 1; + } + for (i = 0; i < n; i++) { device = devs[i];