PCI: pciehp: replace unconditional sleep with config space access check
During reviewing | PCI: pciehp: wait 1000 ms before Link Training check Linus said: >... > That's a *long* time, and it's irritating to the user. It makes the > user think "the machine is slow". >... > And quite frankly, an unconditional one-second delay here seems bad. >Two seconds was unacceptable, one second is just bad. Try to access the pci conf of a pci device that is supposed to show up in 1s. If we can read back a valid vendor/device id, we can return early. Related discussion could be found: https://lkml.org/lkml/2011/12/6/339 -v2: seperate code to pci_bus_read_dev_vendor_id() from pci_scan_device() and reuse it from pciehp code. Suggested by Matthew Wilcox. -v3: According to Kenj, don't use array in stack, and don't wait too long for crs, also return fail status if not found. Also separate pci_bus_dev_read_vendor_id() change to another patch. Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
parent
efdc87dab1
commit
2f5d8e4ff9
|
@ -265,10 +265,37 @@ static void pcie_wait_link_active(struct controller *ctrl)
|
|||
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 count = 0;
|
||||
int delay = 1000, step = 20;
|
||||
bool found = false;
|
||||
|
||||
do {
|
||||
found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0);
|
||||
count++;
|
||||
|
||||
if (found)
|
||||
break;
|
||||
|
||||
msleep(step);
|
||||
delay -= step;
|
||||
} while (delay > 0);
|
||||
|
||||
if (count > 1 && pciehp_debug)
|
||||
printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
|
||||
pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
|
||||
PCI_FUNC(devfn), count, step, l);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
int pciehp_check_link_status(struct controller *ctrl)
|
||||
{
|
||||
u16 lnk_status;
|
||||
int retval = 0;
|
||||
bool found = false;
|
||||
|
||||
/*
|
||||
* Data Link Layer Link Active Reporting must be capable for
|
||||
|
@ -280,13 +307,10 @@ int pciehp_check_link_status(struct controller *ctrl)
|
|||
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);
|
||||
found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
|
||||
PCI_DEVFN(0, 0));
|
||||
|
||||
retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
|
||||
if (retval) {
|
||||
|
@ -302,16 +326,11 @@ int pciehp_check_link_status(struct controller *ctrl)
|
|||
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);
|
||||
|
||||
if (!found && !retval)
|
||||
retval = -1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue