--- drivers/pci/hotplug/pciehp_hpc.c | 47 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) Index: linux-2.6/drivers/pci/hotplug/pciehp_hpc.c =================================================================== --- linux-2.6.orig/drivers/pci/hotplug/pciehp_hpc.c +++ linux-2.6/drivers/pci/hotplug/pciehp_hpc.c @@ -265,6 +265,35 @@ static void pcie_wait_link_active(struct ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); } +static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) +{ + u32 l; + int delay = 1000; + +again: + if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) + goto wait; + + /* some broken boards return 0 or ~0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000 || + l == 0x0000ffff || l == 0xffff0000) + goto wait; + + /* Configuration request Retry Status */ + if (l == 0xffff0001) + goto wait; + + return true; + +wait: + mdelay(100); + delay -= 100; + if (delay > 0) + goto again; + + return false; +} + int pciehp_check_link_status(struct controller *ctrl) { u16 lnk_status; @@ -280,13 +309,9 @@ int pciehp_check_link_status(struct cont else msleep(1000); - /* - * Need to wait for 1000 ms after Data Link Layer Link Active - * (DLLLA) bit reads 1b before sending configuration request. - * We need it before checking Link Training (LT) bit becuase - * LT is still set even after DLLLA bit is set on some platform. - */ - msleep(1000); + /* wait 100ms before read pci conf, and try in 1s */ + msleep(100); + pci_bus_check_dev(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0)); retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { @@ -302,14 +327,6 @@ int pciehp_check_link_status(struct cont return retval; } - /* - * If the port supports Link speeds greater than 5.0 GT/s, we - * must wait for 100 ms after Link training completes before - * sending configuration request. - */ - if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT) - msleep(100); - pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); return retval;