summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2017-08-29 21:45:43 +0200
committerBjorn Helgaas <bhelgaas@google.com>2017-08-29 21:45:43 +0200
commit9f98275671a58516f87b7eb02a3497635861930a (patch)
treee692b90db32c107aab9e3801c71ef4b3d4a539d4 /drivers/pci
parentPCI: Avoid race while enabling upstream bridges (diff)
downloadlinux-9f98275671a58516f87b7eb02a3497635861930a.tar.xz
linux-9f98275671a58516f87b7eb02a3497635861930a.zip
PCI: Always check for non-CRS response before timeout
While waiting for a device to become ready (i.e., to return a non-CRS completion to a read of its Vendor ID), if we got a valid response to the very last read before timing out, we printed a warning and gave up on the device even though it was actually ready. For a typical 60s timeout, we wait about 65s (it's not exact because of the exponential backoff), but we treated devices that became ready between 33s and 65s as though they failed. Move the Device ID read later so we check whether the device is ready before checking for a timeout. Thanks to Sinan Kaya <okaya@codeaurora.org>, reorder reads so we always check device presence after sleep, since it's pointless to sleep unless we recheck afterwards. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/probe.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c81c9835f4c7..150093817c59 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1876,17 +1876,18 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
if (!crs_timeout)
return false;
- msleep(delay);
- delay *= 2;
- if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
- return false;
- /* Card hasn't responded in 60 seconds? Must be stuck. */
if (delay > crs_timeout) {
printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not responding\n",
pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn));
return false;
}
+
+ msleep(delay);
+ delay *= 2;
+
+ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+ return false;
}
return true;