@@ -4982,7 +4982,19 @@ void pci_reset_secondary_bus(struct pci_dev *dev)
void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
{
+ struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
+ int ret;
+
+ if (host->reset_slot) {
+ ret = host->reset_slot(host, dev);
+ if (ret)
+ pci_err(dev, "failed to reset slot: %d\n", ret);
+
+ return;
+ }
+
pci_reset_secondary_bus(dev);
+
}
/**
@@ -234,11 +234,6 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
}
if (status == PCI_ERS_RESULT_NEED_RESET) {
- /*
- * TODO: Should call platform-specific
- * functions to reset slot before calling
- * drivers' slot_reset callbacks?
- */
status = PCI_ERS_RESULT_RECOVERED;
pci_dbg(bridge, "broadcast slot_reset message\n");
pci_walk_bridge(bridge, report_slot_reset, &status);
@@ -599,6 +599,7 @@ struct pci_host_bridge {
void (*release_fn)(struct pci_host_bridge *);
int (*enable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev);
void (*disable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev);
+ int (*reset_slot)(struct pci_host_bridge *bridge, struct pci_dev *dev);
void *release_data;
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
unsigned int no_ext_tags:1; /* No Extended Tags */
Some host bridge devices require resetting the slots in a platform specific way to recover them from error conditions such as Fatal AER errors, Link Down etc... So introduce pci_host_bridge::reset_slot callback and call it from pcibios_reset_secondary_bus() if available. The 'reset_slot' callback is responsible for resetting the given slot referenced by the 'pci_dev' pointer in a platform specific way and bring it back to the working state if possible. If any error occurs during the slot reset operation, relevant errno should be returned. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> --- drivers/pci/pci.c | 12 ++++++++++++ drivers/pci/pcie/err.c | 5 ----- include/linux/pci.h | 1 + 3 files changed, 13 insertions(+), 5 deletions(-)