Commit 08e3ed12 authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Bjorn Helgaas

PCI: Add failed link recovery for device reset events

Request failed link recovery with any upstream PCIe bridge where a device
has not come back after reset within PCI_RESET_WAIT time.  Reset the
polling interval if recovery succeeded, otherwise continue as usual.

[bhelgaas: inline pcie_parent_link_retrain()]
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2306111631050.64925@angie.orcam.me.ukSigned-off-by: default avatarMaciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent a89c8224
...@@ -1156,7 +1156,14 @@ void pci_resume_bus(struct pci_bus *bus) ...@@ -1156,7 +1156,14 @@ void pci_resume_bus(struct pci_bus *bus)
static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
{ {
int delay = 1; int delay = 1;
u32 id; bool retrain = false;
struct pci_dev *bridge;
if (pci_is_pcie(dev)) {
bridge = pci_upstream_bridge(dev);
if (bridge)
retrain = true;
}
/* /*
* After reset, the device should not silently discard config * After reset, the device should not silently discard config
...@@ -1170,21 +1177,33 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) ...@@ -1170,21 +1177,33 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
* Command register instead of Vendor ID so we don't have to * Command register instead of Vendor ID so we don't have to
* contend with the CRS SV value. * contend with the CRS SV value.
*/ */
pci_read_config_dword(dev, PCI_COMMAND, &id); for (;;) {
while (PCI_POSSIBLE_ERROR(id)) { u32 id;
pci_read_config_dword(dev, PCI_COMMAND, &id);
if (!PCI_POSSIBLE_ERROR(id))
break;
if (delay > timeout) { if (delay > timeout) {
pci_warn(dev, "not ready %dms after %s; giving up\n", pci_warn(dev, "not ready %dms after %s; giving up\n",
delay - 1, reset_type); delay - 1, reset_type);
return -ENOTTY; return -ENOTTY;
} }
if (delay > PCI_RESET_WAIT) if (delay > PCI_RESET_WAIT) {
if (retrain) {
retrain = false;
if (pcie_failed_link_retrain(bridge)) {
delay = 1;
continue;
}
}
pci_info(dev, "not ready %dms after %s; waiting\n", pci_info(dev, "not ready %dms after %s; waiting\n",
delay - 1, reset_type); delay - 1, reset_type);
}
msleep(delay); msleep(delay);
delay *= 2; delay *= 2;
pci_read_config_dword(dev, PCI_COMMAND, &id);
} }
if (delay > PCI_RESET_WAIT) if (delay > PCI_RESET_WAIT)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment