From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> If hotplug is supported, during DPC event, hotplug driver would remove the affected devices and detach the drivers on DLLSC link down event and will re-enumerate it once the DPC recovery is handled and link comes back online (on DLLSC LINK up event). Hence we don't depend on .mmio_enabled or .slot_reset callbacks in error recovery handler to restore the device. But if hotplug is not supported/enabled, then we need to let the error recovery handler attempt the recovery of the devices using slot reset. So if hotplug is not supported, then instead of returning PCI_ERS_RESULT_RECOVERED, return PCI_ERS_RESULT_NEED_RESET. Also modify the way error recovery handler processes the recovery value. Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> --- drivers/pci/pcie/dpc.c | 8 ++++++++ drivers/pci/pcie/err.c | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index e06f42f58d3d..0e356ed0d73f 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -13,6 +13,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include "portdrv.h" #include "../pci.h" @@ -144,6 +145,13 @@ static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) if (!pcie_wait_for_link(pdev, true)) return PCI_ERS_RESULT_DISCONNECT; + /* + * If hotplug is not supported/enabled then let the device + * recover using slot reset. + */ + if (!hotplug_is_native(pdev)) + return PCI_ERS_RESULT_NEED_RESET; + return PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 1ac57e9e1e71..6e52591a4722 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -178,7 +178,8 @@ static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service) return PCI_ERS_RESULT_DISCONNECT; } - if (status != PCI_ERS_RESULT_RECOVERED) { + if ((status != PCI_ERS_RESULT_RECOVERED) && + (status != PCI_ERS_RESULT_NEED_RESET)) { pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n", pci_name(dev)); return PCI_ERS_RESULT_DISCONNECT; @@ -206,7 +207,7 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, if (state == pci_channel_io_frozen) { pci_walk_bus(bus, report_frozen_detected, &status); status = reset_link(dev, service); - if (status != PCI_ERS_RESULT_RECOVERED) + if (status == PCI_ERS_RESULT_DISCONNECT) goto failed; } else { pci_walk_bus(bus, report_normal_detected, &status); -- 2.17.1