Prarit, FYI, this patch does the trick on Draco. I'll try it in the Stratus lab as well, but I'm 99.99% sure that it will work there too. There was one concern when we had a meeting at Stratus to talk about this: we're not sure if the NEC-branded systems have the same DMI string or not... I'm trying to find out. --jim ----- Original Message ----- > Trying [v2].... > > > pci: Workaround Stratus broken PCIE hierarchy > > Stratus systems have a hierarchy that includes a PCIE Downstream > bridge > connected to a PCIE Upstream bridge and a PCI Downstream bridge. The > system > boots with this wrong hierarchy into a crippled mode (USB doesn't > work, > network doesn't work ...). Avoiding the Downstream bridge check in > only_one_child() causes all the bridges to be enumerated and the > system > to function properly. > > Unfortunately this hardware is currently available so we should at > least > keep it functional. > > [v2] > - ddutile@xxxxxxxxxx requested drivers/pci/quirks.c code > - matthew@xxxxxxx requested that dmi_name_in_vendors() be called only > once with a static var check > - added a kernel parameter to enable scanning of all PCIE devices. > > Signed-off-by: Prarit Bhargava <prarit@xxxxxxxxxx> > > diff --git a/Documentation/kernel-parameters.txt > b/Documentation/kernel-parameters.txt > index a0c5c5f..7af458f 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -2069,6 +2069,7 @@ bytes respectively. Such letter suffixes can > also be entirely omitted. > on: Turn ECRC on. > realloc reallocate PCI resources if allocations done by BIOS > are erroneous. > + pcie_scan_all Scan all possible PCIE devices. > > pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State > Power > Management. > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 6f45a73..f478bd5 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -3589,6 +3589,9 @@ static int __init pci_setup(char *str) > pcie_bus_config = PCIE_BUS_PERFORMANCE; > } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) { > pcie_bus_config = PCIE_BUS_PEER2PEER; > + } else if (!strncmp(str, "pcie_scan_all", 13)) { > + printk(KERN_ERR HW_ERR "PCIE: Scanning all devices.\n"); > + pcie_scan_all = 1; > } else { > printk(KERN_ERR "PCI: Unknown option `%s'\n", > str); > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h > index b74084e..5a07895 100644 > --- a/drivers/pci/pci.h > +++ b/drivers/pci/pci.h > @@ -309,11 +309,16 @@ struct pci_dev_reset_methods { > > #ifdef CONFIG_PCI_QUIRKS > extern int pci_dev_specific_reset(struct pci_dev *dev, int probe); > +extern int is_broken_pcie_port(void); > #else > static inline int pci_dev_specific_reset(struct pci_dev *dev, int > probe) > { > return -ENOTTY; > } > +static inline int is_broken_pcie_port(void) > +{ > + return 0; > +} > #endif > > #endif /* DRIVERS_PCI_H */ > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 04e74f4..fc88a9b 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -1270,13 +1270,18 @@ static unsigned no_next_fn(struct pci_dev > *dev, unsigned fn) > return 0; > } > > +int pcie_scan_all = 0; /* set via pci=pcie_scan_all */ > static int only_one_child(struct pci_bus *bus) > { > struct pci_dev *parent = bus->self; > + if (pcie_scan_all) > + return 0; > if (!parent || !pci_is_pcie(parent)) > return 0; > - if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT || > - parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) > + if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT) > + return 1; > + if (parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM && > + !is_broken_pcie_port()) > return 1; > return 0; > } > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index 7285145..ef4d0e7 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3092,3 +3092,21 @@ int pci_dev_specific_reset(struct pci_dev > *dev, int probe) > > return -ENOTTY; > } > + > +static int _is_broken_pcie_port = -1; > +int is_broken_pcie_port(void) > +{ > + if (_is_broken_pcie_port >= 0) > + return _is_broken_pcie_port; > + /* > + * Stratus/NEC ftServer systems have a broken PCIE hierarchy in > which > + * one upstream and one downstream port are plugged into a > downstream > + * port. Avoiding the downstream port check in only_one_child() > results > + * in a functional system. > + */ > + if (dmi_name_in_vendors("ftServer")) > + _is_broken_pcie_port = 1; > + else > + _is_broken_pcie_port = 0; > + return _is_broken_pcie_port; > +} > diff --git a/include/linux/pci.h b/include/linux/pci.h > index 337df0d..745b98e 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -1647,5 +1647,7 @@ static inline void > pci_release_bus_of_node(struct pci_bus *bus) { } > */ > struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); > > +/* set via pci=pcie_scan_all in order to enumerate all possible PCIE > busses */ > +extern int pcie_scan_all; > #endif /* __KERNEL__ */ > #endif /* LINUX_PCI_H */ > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html