@@ -4608,7 +4608,8 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
* pcie_wait_for_link_delay - Wait until link is active or inactive
* @pdev: Bridge device
* @active: waiting for active or inactive?
- * @delay: Delay to wait after link has become active (in ms)
+ * @delay: Delay to wait after link has become active (in ms). Specify %0
+ * for no delay.
*
* Use this to wait till link becomes active or inactive.
*/
@@ -4649,7 +4650,7 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
msleep(10);
timeout -= 10;
}
- if (active && ret)
+ if (active && ret && delay)
msleep(delay);
else if (ret != active)
pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
@@ -4770,17 +4771,28 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
if (!pcie_downstream_port(dev))
return;
- if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
- pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
- msleep(delay);
- } else {
- pci_dbg(dev, "waiting %d ms for downstream link, after activation\n",
- delay);
- if (!pcie_wait_for_link_delay(dev, true, delay)) {
+ /*
+ * Per PCIe r5.0, sec 6.6.1, for downstream ports that support
+ * speeds > 5 GT/s, we must wait for link training to complete
+ * before the mandatory delay.
+ *
+ * We can only tell when link training completes via DLL Link
+ * Active, which is required for downstream ports that support
+ * speeds > 5 GT/s (sec 7.5.3.6). Unfortunately some common
+ * devices do not implement Link Active reporting even when it's
+ * required, so we'll check for that directly instead of checking
+ * the supported link speed. We assume devices without Link Active
+ * reporting can train in 100 ms regardless of speed.
+ */
+ if (dev->link_active_reporting) {
+ pci_dbg(dev, "waiting for link to train\n");
+ if (!pcie_wait_for_link_delay(dev, true, 0)) {
/* Did not train, no need to wait any further */
return;
}
}
+ pci_dbg(child, "waiting %d ms to become accessible\n", delay);
+ msleep(delay);
if (!pci_device_is_present(child)) {
pci_dbg(child, "waiting additional %d ms to become accessible\n", delay);