diff options
| -rw-r--r-- | drivers/pci/controller/pci-host-common.c | 35 | ||||
| -rw-r--r-- | drivers/pci/controller/pci-host-common.h | 1 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 1 | ||||
| -rw-r--r-- | drivers/pci/pcie/err.c | 1 |
4 files changed, 38 insertions, 0 deletions
diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index 2ce6f4b66133..363d3f970b10 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -13,9 +13,11 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_pci.h> +#include <linux/pci.h> #include <linux/pci-ecam.h> #include <linux/platform_device.h> +#include "../pci.h" #include "pci-host-common.h" /** @@ -342,5 +344,38 @@ bool pci_host_common_d3cold_possible(struct pci_host_bridge *bridge, } EXPORT_SYMBOL_GPL(pci_host_common_d3cold_possible); +static pci_ers_result_t pci_host_reset_root_port(struct pci_dev *dev) +{ + int ret; + + pci_lock_rescan_remove(); + ret = pci_bus_error_reset(dev); + pci_unlock_rescan_remove(); + if (ret) { + pci_err(dev, "Failed to reset Root Port: %d\n", ret); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_info(dev, "Root Port has been reset\n"); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void pci_host_recover_root_port(struct pci_dev *port) +{ +#if IS_ENABLED(CONFIG_PCIEAER) + pcie_do_recovery(port, pci_channel_io_frozen, pci_host_reset_root_port); +#else + pci_host_reset_root_port(port); +#endif +} + +void pci_host_handle_link_down(struct pci_dev *port) +{ + pci_info(port, "Recovering Root Port due to Link Down\n"); + pci_host_recover_root_port(port); +} +EXPORT_SYMBOL_GPL(pci_host_handle_link_down); + MODULE_DESCRIPTION("Common library for PCI host controller drivers"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/controller/pci-host-common.h b/drivers/pci/controller/pci-host-common.h index 9f0f36a32221..51afd65d3c4a 100644 --- a/drivers/pci/controller/pci-host-common.h +++ b/drivers/pci/controller/pci-host-common.h @@ -48,6 +48,7 @@ int pci_host_common_init(struct platform_device *pdev, struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops); void pci_host_common_remove(struct platform_device *pdev); +void pci_host_handle_link_down(struct pci_dev *port); struct pci_config_window *pci_host_common_ecam_create(struct device *dev, struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 12e099489690..ff6d5d059b21 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5700,6 +5700,7 @@ int pci_bus_error_reset(struct pci_dev *bridge) { return pci_reset_bridge(bridge, PCI_RESET_NO_RESTORE); } +EXPORT_SYMBOL_GPL(pci_bus_error_reset); int pci_try_reset_bridge(struct pci_dev *bridge) { diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 13b9d9eb714f..d77403d8855b 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -292,3 +292,4 @@ failed: return status; } +EXPORT_SYMBOL_GPL(pcie_do_recovery); |
