@@ -966,6 +966,7 @@ int pci_aer_clear_status(struct pci_dev *dev);
int pci_aer_raw_clear_status(struct pci_dev *dev);
void pci_save_aer_state(struct pci_dev *dev);
void pci_restore_aer_state(struct pci_dev *dev);
+void pcie_do_recover_slots(struct pci_host_bridge *host);
#else
static inline void pci_no_aer(void) { }
static inline void pci_aer_init(struct pci_dev *d) { }
@@ -975,6 +976,27 @@ static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline void pci_save_aer_state(struct pci_dev *dev) { }
static inline void pci_restore_aer_state(struct pci_dev *dev) { }
+static inline void pcie_do_recover_slots(struct pci_host_bridge *host)
+{
+ struct pci_bus *bus = host->bus;
+ struct pci_dev *dev;
+ int ret;
+
+ if (!host->reset_slot) {
+ dev_warn(&host->dev, "Missing reset_slot() callback\n");
+ return;
+ }
+
+ for_each_pci_bridge(dev, bus) {
+ ret = host->reset_slot(host, dev);
+ if (ret)
+ dev_err(&host->dev, "failed to reset slot (%s): %d\n",
+ pci_name(dev), ret);
+ else
+ dev_dbg(&host->dev, "recovered slot (%s)\n",
+ pci_name(dev));
+ }
+}
#endif
#ifdef CONFIG_ACPI
@@ -196,6 +196,7 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
struct pci_dev *bridge;
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
+ int ret;
/*
* If the error was detected by a Root Port, Downstream Port, RCEC,
@@ -219,7 +220,8 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
pci_dbg(bridge, "broadcast error_detected message\n");
if (state == pci_channel_io_frozen) {
pci_walk_bridge(bridge, report_frozen_detected, &status);
- if (reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED) {
+ if (reset_subordinates && reset_subordinates(bridge) !=
+ PCI_ERS_RESULT_RECOVERED) {
pci_warn(bridge, "subordinate device reset failed\n");
goto failed;
}
@@ -280,3 +282,12 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
return status;
}
+
+void pcie_do_recover_slots(struct pci_host_bridge *host)
+{
+ struct pci_bus *bus = host->bus;
+ struct pci_dev *dev;
+
+ for_each_pci_bridge(dev, bus)
+ pcie_do_recovery(dev, pci_channel_io_frozen, NULL);
+}
@@ -3249,6 +3249,13 @@ int pci_host_probe(struct pci_host_bridge *bridge)
}
EXPORT_SYMBOL_GPL(pci_host_probe);
+void pci_host_handle_link_down(struct pci_host_bridge *bridge)
+{
+ dev_info(&bridge->dev, "Recovering slots due to Link Down\n");
+ pcie_do_recover_slots(bridge);
+}
+EXPORT_SYMBOL_GPL(pci_host_handle_link_down);
+
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
{
struct resource *res = &b->busn_res;
@@ -1157,6 +1157,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
int pci_host_probe(struct pci_host_bridge *bridge);
+void pci_host_handle_link_down(struct pci_host_bridge *bridge);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
void pci_bus_release_busn_res(struct pci_bus *b);