diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 1c381d3c7095..d7665ac93b40 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -72,6 +72,8 @@ static DEFINE_SPINLOCK(time_sync_lock); #define POWER_ON_RETRY_MAX_TIMES 3 #define POWER_ON_RETRY_DELAY_MS 200 +#define LINK_TRAINING_RETRY_MAX_TIMES 3 + static struct cnss_pci_reg ce_src[] = { { "SRC_RING_BASE_LSB", QCA6390_CE_SRC_RING_BASE_LSB_OFFSET }, { "SRC_RING_BASE_MSB", QCA6390_CE_SRC_RING_BASE_MSB_OFFSET }, @@ -695,6 +697,7 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up) int ret = 0; struct pci_dev *pci_dev = pci_priv->pci_dev; enum msm_pcie_pm_opt pm_ops; + int retry = 0; cnss_pr_vdbg("%s PCI link\n", link_up ? "Resuming" : "Suspending"); @@ -710,11 +713,17 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up) } } +retry: ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev, NULL, PM_OPTIONS_DEFAULT); - if (ret) + if (ret) { cnss_pr_err("Failed to %s PCI link with default option, err = %d\n", link_up ? "resume" : "suspend", ret); + if (link_up && retry++ < LINK_TRAINING_RETRY_MAX_TIMES) { + cnss_pr_dbg("Retry PCI link training #%d\n", retry); + goto retry; + } + } if (pci_priv->drv_connected_last) { if ((link_up && !ret) || (!link_up && ret)) @@ -4336,6 +4345,7 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv) int ret = 0; struct device *dev = &plat_priv->plat_dev->dev; u32 rc_num; + int retry = 0; ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num); if (ret) { @@ -4343,11 +4353,17 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv) goto out; } +retry: ret = msm_pcie_enumerate(rc_num); if (ret) { cnss_pr_err("Failed to enable PCIe RC%x, err = %d\n", rc_num, ret); - goto out; + if (retry++ < LINK_TRAINING_RETRY_MAX_TIMES) { + cnss_pr_dbg("Retry PCI link training #%d\n", retry); + goto retry; + } else { + goto out; + } } ret = pci_register_driver(&cnss_pci_driver);