Jiri Slaby ef7db2
From: Lukas Wunner <lukas@wunner.de>
Jiri Slaby ef7db2
Date: Sun, 15 Jan 2023 09:20:33 +0100
Jiri Slaby ef7db2
Subject: [PATCH] PCI/DPC: Await readiness of secondary bus after reset
Jiri Slaby ef7db2
References: bsc#1012628
Jiri Slaby ef7db2
Patch-mainline: 6.2.3
Jiri Slaby ef7db2
Git-commit: 53b54ad074de1896f8b021615f65b27f557ce874
Jiri Slaby ef7db2
Jiri Slaby ef7db2
commit 53b54ad074de1896f8b021615f65b27f557ce874 upstream.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
pci_bridge_wait_for_secondary_bus() is called after a Secondary Bus
Jiri Slaby ef7db2
Reset, but not after a DPC-induced Hot Reset.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
As a result, the delays prescribed by PCIe r6.0 sec 6.6.1 are not
Jiri Slaby ef7db2
observed and devices on the secondary bus may be accessed before
Jiri Slaby ef7db2
they're ready.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
One affected device is Intel's Ponte Vecchio HPC GPU.  It comprises a
Jiri Slaby ef7db2
PCIe switch whose upstream port is not immediately ready after reset.
Jiri Slaby ef7db2
Because its config space is restored too early, it remains in
Jiri Slaby ef7db2
D0uninitialized, its subordinate devices remain inaccessible and DPC
Jiri Slaby ef7db2
recovery fails with messages such as:
Jiri Slaby ef7db2
Jiri Slaby ef7db2
  i915 0000:8c:00.0: can't change power state from D3cold to D0 (config space inaccessible)
Jiri Slaby ef7db2
  intel_vsec 0000:8e:00.1: can't change power state from D3cold to D0 (config space inaccessible)
Jiri Slaby ef7db2
  pcieport 0000:89:02.0: AER: device recovery failed
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Fix it.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Link: https://lore.kernel.org/r/9f5ff00e1593d8d9a4b452398b98aa14d23fca11.1673769517.git.lukas@wunner.de
Jiri Slaby ef7db2
Tested-by: Ravi Kishore Koppuravuri <ravi.kishore.koppuravuri@intel.com>
Jiri Slaby ef7db2
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Jiri Slaby ef7db2
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Jiri Slaby ef7db2
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Jiri Slaby ef7db2
Cc: stable@vger.kernel.org
Jiri Slaby ef7db2
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jiri Slaby ef7db2
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby ef7db2
---
Jiri Slaby ef7db2
 drivers/pci/pci.c      | 3 ---
Jiri Slaby ef7db2
 drivers/pci/pci.h      | 6 ++++++
Jiri Slaby ef7db2
 drivers/pci/pcie/dpc.c | 4 ++--
Jiri Slaby ef7db2
 3 files changed, 8 insertions(+), 5 deletions(-)
Jiri Slaby ef7db2
Jiri Slaby ef7db2
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
Jiri Slaby ef7db2
index 108c6ce5..da748247 100644
Jiri Slaby ef7db2
--- a/drivers/pci/pci.c
Jiri Slaby ef7db2
+++ b/drivers/pci/pci.c
Jiri Slaby ef7db2
@@ -167,9 +167,6 @@ static int __init pcie_port_pm_setup(char *str)
Jiri Slaby ef7db2
 }
Jiri Slaby ef7db2
 __setup("pcie_port_pm=", pcie_port_pm_setup);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-/* Time to wait after a reset for device to become responsive */
Jiri Slaby ef7db2
-#define PCIE_RESET_READY_POLL_MS 60000
Jiri Slaby ef7db2
-
Jiri Slaby ef7db2
 /**
Jiri Slaby ef7db2
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
Jiri Slaby ef7db2
  * @bus: pointer to PCI bus structure to search
Jiri Slaby ef7db2
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
Jiri Slaby ef7db2
index 44643ffb..d2c08670 100644
Jiri Slaby ef7db2
--- a/drivers/pci/pci.h
Jiri Slaby ef7db2
+++ b/drivers/pci/pci.h
Jiri Slaby ef7db2
@@ -70,6 +70,12 @@ struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
Jiri Slaby ef7db2
  * Reset (PCIe r6.0 sec 5.8).
Jiri Slaby ef7db2
  */
Jiri Slaby ef7db2
 #define PCI_RESET_WAIT		1000	/* msec */
Jiri Slaby ef7db2
+/*
Jiri Slaby ef7db2
+ * Devices may extend the 1 sec period through Request Retry Status completions
Jiri Slaby ef7db2
+ * (PCIe r6.0 sec 2.3.1).  The spec does not provide an upper limit, but 60 sec
Jiri Slaby ef7db2
+ * ought to be enough for any device to become responsive.
Jiri Slaby ef7db2
+ */
Jiri Slaby ef7db2
+#define PCIE_RESET_READY_POLL_MS 60000	/* msec */
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
Jiri Slaby ef7db2
 void pci_refresh_power_state(struct pci_dev *dev);
Jiri Slaby ef7db2
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
Jiri Slaby ef7db2
index f5ffea17..a5d7c69b 100644
Jiri Slaby ef7db2
--- a/drivers/pci/pcie/dpc.c
Jiri Slaby ef7db2
+++ b/drivers/pci/pcie/dpc.c
Jiri Slaby ef7db2
@@ -170,8 +170,8 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
Jiri Slaby ef7db2
 	pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
Jiri Slaby ef7db2
 			      PCI_EXP_DPC_STATUS_TRIGGER);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-	if (!pcie_wait_for_link(pdev, true)) {
Jiri Slaby ef7db2
-		pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
Jiri Slaby ef7db2
+	if (pci_bridge_wait_for_secondary_bus(pdev, "DPC",
Jiri Slaby ef7db2
+					      PCIE_RESET_READY_POLL_MS)) {
Jiri Slaby ef7db2
 		clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
Jiri Slaby ef7db2
 		ret = PCI_ERS_RESULT_DISCONNECT;
Jiri Slaby ef7db2
 	} else {
Jiri Slaby ef7db2
-- 
Jiri Slaby ef7db2
2.35.3
Jiri Slaby ef7db2