diff mbox series

[v3,01/17] PCI: Fall back to slot/bus reset if softer methods timeout

Message ID 20200303132852.13184-2-stanspas@amazon.com (mailing list archive)
State Superseded, archived
Headers show
Series Improve PCI device post-reset readiness polling | expand

Commit Message

Stanislav Spassov March 3, 2020, 1:28 p.m. UTC
From: Stanislav Spassov <stanspas@amazon.de>

Previously, if a device never came back (i.e., never started returning
Successful Completions for Configuration Requests) after a reset, they
would return -ENOTTY, causing __pci_reset_function_locked to move on
to the next reset method.

However, up until slot/bus reset, all of them rely on the device being
responsive and are therefore not safe to attempt in this situation.

This patch introduces ETIMEDOUT as a new, specially handled return value
for the reset methods (which all end in "return pci_dev_wait"), to allow
skipping to slot/bus reset where appropriate.

Signed-off-by: Stanislav Spassov <stanspas@amazon.de>
---
 drivers/pci/pci.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d828ca835a98..ac8504d75c32 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1043,7 +1043,7 @@  static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
 		if (delay > timeout) {
 			pci_warn(dev, "not ready %dms after %s; giving up\n",
 				 delay - 1, reset_type);
-			return -ENOTTY;
+			return -ETIMEDOUT;
 		}
 
 		if (delay > 1000)
@@ -4845,6 +4845,7 @@  static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
 	if (probe)
 		return 0;
 
+	/* XXX: Shouldn't this lock the bus? */
 	return pci_bridge_secondary_bus_reset(dev->bus->self);
 }
 
@@ -4979,25 +4980,37 @@  int __pci_reset_function_locked(struct pci_dev *dev)
 	/*
 	 * A reset method returns -ENOTTY if it doesn't support this device
 	 * and we should try the next method.
+	 * It returns -ETIMEDOUT if the device never became responsive after
+	 * the reset: we jump to the reset types that do not rely on config
+	 * space access (if any are left).
 	 *
-	 * If it returns 0 (success), we're finished.  If it returns any
-	 * other error, we're also finished: this indicates that further
-	 * reset mechanisms might be broken on the device.
+	 * If it returns 0 (success), we are finished.
+	 * If it returns any other error, we are finished (something must have
+	 * went terribly wrong and it is not safe to continue reset attempts).
 	 */
 	rc = pci_dev_specific_reset(dev, 0);
+	if (rc == -ETIMEDOUT)
+		goto unresponsive;
 	if (rc != -ENOTTY)
 		return rc;
 	if (pcie_has_flr(dev)) {
 		rc = pcie_flr(dev);
+		if (rc == -ETIMEDOUT)
+			goto unresponsive;
 		if (rc != -ENOTTY)
 			return rc;
 	}
 	rc = pci_af_flr(dev, 0);
+	if (rc == -ETIMEDOUT)
+		goto unresponsive;
 	if (rc != -ENOTTY)
 		return rc;
 	rc = pci_pm_reset(dev, 0);
+	if (rc == -ETIMEDOUT)
+		goto unresponsive;
 	if (rc != -ENOTTY)
 		return rc;
+unresponsive:
 	rc = pci_dev_reset_slot_function(dev, 0);
 	if (rc != -ENOTTY)
 		return rc;