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.uk Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
committed by
Bjorn Helgaas
parent
a89c82249c
commit
08e3ed12ca
+24
-5
@@ -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)
|
||||
{
|
||||
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
|
||||
@@ -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
|
||||
* contend with the CRS SV value.
|
||||
*/
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
||||
while (PCI_POSSIBLE_ERROR(id)) {
|
||||
for (;;) {
|
||||
u32 id;
|
||||
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
||||
if (!PCI_POSSIBLE_ERROR(id))
|
||||
break;
|
||||
|
||||
if (delay > timeout) {
|
||||
pci_warn(dev, "not ready %dms after %s; giving up\n",
|
||||
delay - 1, reset_type);
|
||||
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",
|
||||
delay - 1, reset_type);
|
||||
}
|
||||
|
||||
msleep(delay);
|
||||
delay *= 2;
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
||||
}
|
||||
|
||||
if (delay > PCI_RESET_WAIT)
|
||||
|
||||
Reference in New Issue
Block a user