[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <alpine.DEB.2.21.2306111631050.64925@angie.orcam.me.uk>
Date: Sun, 11 Jun 2023 18:20:06 +0100 (BST)
From: "Maciej W. Rozycki" <macro@...am.me.uk>
To: Bjorn Helgaas <bhelgaas@...gle.com>,
Mahesh J Salgaonkar <mahesh@...ux.ibm.com>,
Oliver O'Halloran <oohall@...il.com>,
Michael Ellerman <mpe@...erman.id.au>,
Nicholas Piggin <npiggin@...il.com>,
Christophe Leroy <christophe.leroy@...roup.eu>,
Saeed Mahameed <saeedm@...dia.com>,
Leon Romanovsky <leon@...nel.org>,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>
cc: Alex Williamson <alex.williamson@...hat.com>,
Lukas Wunner <lukas@...ner.de>,
Mika Westerberg <mika.westerberg@...ux.intel.com>,
Stefan Roese <sr@...x.de>, Jim Wilson <wilson@...iptree.org>,
David Abdurachmanov <david.abdurachmanov@...il.com>,
Pali Rohár <pali@...nel.org>,
linux-pci@...r.kernel.org, linuxppc-dev@...ts.ozlabs.org,
linux-rdma@...r.kernel.org, netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH v9 13/14] PCI: Add failed link recovery for device reset
events
Request failed link recovery with any upstream 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.
Signed-off-by: Maciej W. Rozycki <macro@...am.me.uk>
---
New change in v9, factored out from 7/7:
- Remove duplicate succesful completion report previously added (not sure
where it came from, possibly an unnoticed leftover from experiments).
- Make the type of `retrain' variable `bool' rather than `int' and invert
the logic used.
- Rename `pcie_downstream_link_retrain' to `pcie_failed_link_retrain'.
- Rename `pcie_upstream_link_retrain' to `pcie_parent_link_retrain'. Add
documentation.
---
drivers/pci/pci.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
linux-pcie-dev-wait-link-retrain.diff
Index: linux-macro/drivers/pci/pci.c
===================================================================
--- linux-macro.orig/drivers/pci/pci.c
+++ linux-macro/drivers/pci/pci.c
@@ -1146,10 +1146,27 @@ void pci_resume_bus(struct pci_bus *bus)
pci_walk_bus(bus, pci_resume_one, NULL);
}
+/**
+ * pcie_parent_link_retrain - Check and retrain link we are downstream from
+ * @dev: PCI device to handle.
+ *
+ * Return TRUE if the link was retrained, FALSE otherwise.
+ */
+static bool pcie_parent_link_retrain(struct pci_dev *dev)
+{
+ struct pci_dev *bridge;
+
+ bridge = pci_upstream_bridge(dev);
+ if (bridge)
+ return pcie_failed_link_retrain(bridge);
+ else
+ return false;
+}
+
static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
{
+ bool retrain = true;
int delay = 1;
- u32 id;
/*
* After reset, the device should not silently discard config
@@ -1163,21 +1180,33 @@ static int pci_dev_wait(struct pci_dev *
* 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_parent_link_retrain(dev)) {
+ 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)
Powered by blists - more mailing lists