Commit 238eb0d9 authored by Lukas Wunner's avatar Lukas Wunner Committed by sanglipeng
Browse files

PCI/DPC: Await readiness of secondary bus after reset

stable inclusion
from stable-v5.10.176
commit d0292124bb5787a2f1ab1316509e801ca89c10fb
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I87BGI

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=d0292124bb5787a2f1ab1316509e801ca89c10fb

--------------------------------

commit 53b54ad0 upstream.

pci_bridge_wait_for_secondary_bus() is called after a Secondary Bus
Reset, but not after a DPC-induced Hot Reset.

As a result, the delays prescribed by PCIe r6.0 sec 6.6.1 are not
observed and devices on the secondary bus may be accessed before
they're ready.

One affected device is Intel's Ponte Vecchio HPC GPU.  It comprises a
PCIe switch whose upstream port is not immediately ready after reset.
Because its config space is restored too early, it remains in
D0uninitialized, its subordinate devices remain inaccessible and DPC
recovery fails with messages such as:

  i915 0000:8c:00.0: can't change power state from D3cold to D0 (config space inaccessible)
  intel_vsec 0000:8e:00.1: can't change power state from D3cold to D0 (config space inaccessible)
  pcieport 0000:89:02.0: AER: device recovery failed

Fix it.

Link: https://lore.kernel.org/r/9f5ff00e1593d8d9a4b452398b98aa14d23fca11.1673769517.git.lukas@wunner.de


Tested-by: default avatarRavi Kishore Koppuravuri <ravi.kishore.koppuravuri@intel.com>
Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarsanglipeng <sanglipeng1@jd.com>
parent 6bbaefd8
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -169,9 +169,6 @@ static int __init pcie_port_pm_setup(char *str)
}
__setup("pcie_port_pm=", pcie_port_pm_setup);

/* Time to wait after a reset for device to become responsive */
#define PCIE_RESET_READY_POLL_MS 60000

/**
 * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
 * @bus: pointer to PCI bus structure to search
+6 −0
Original line number Diff line number Diff line
@@ -53,6 +53,12 @@ int pci_bus_error_reset(struct pci_dev *dev);
 * Reset (PCIe r6.0 sec 5.8).
 */
#define PCI_RESET_WAIT		1000	/* msec */
/*
 * Devices may extend the 1 sec period through Request Retry Status completions
 * (PCIe r6.0 sec 2.3.1).  The spec does not provide an upper limit, but 60 sec
 * ought to be enough for any device to become responsive.
 */
#define PCIE_RESET_READY_POLL_MS 60000	/* msec */

/**
 * struct pci_platform_pm_ops - Firmware PM callbacks
+2 −2
Original line number Diff line number Diff line
@@ -170,8 +170,8 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
	pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
			      PCI_EXP_DPC_STATUS_TRIGGER);

	if (!pcie_wait_for_link(pdev, true)) {
		pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
	if (pci_bridge_wait_for_secondary_bus(pdev, "DPC",
					      PCIE_RESET_READY_POLL_MS)) {
		clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
		ret = PCI_ERS_RESULT_DISCONNECT;
	} else {