From 2cf1df2b58b545780baee47ccf6de6f045377eaa Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Tue, 11 Aug 2020 15:10:59 -0700 Subject: [PATCH] cnss2: Notify MSM PCIe bus driver when detect link down There are cases that CNSS driver or WLAN host driver detects PCIe link not accessible but link down interrupt is not triggered. In order to handle these cases, instead of starting recovery directly, notify MSM PCIe bus which can assert PCIe PERST GPIO and then handle the link down callback from it as normal link down. Change-Id: I9af8b3ae33d9c094a412c39962f5c1883c34a12a Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/pci.c | 66 +++++++++++++++----------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index e7c6ba369380..f2d980fe0571 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -912,19 +912,12 @@ void cnss_pci_allow_l1(struct device *dev) } EXPORT_SYMBOL(cnss_pci_allow_l1); -int cnss_pci_link_down(struct device *dev) +static void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv) { + struct cnss_plat_data *plat_priv = pci_priv->plat_priv; + struct pci_dev *pci_dev = pci_priv->pci_dev; unsigned long flags; - struct pci_dev *pci_dev = to_pci_dev(dev); - struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); - struct cnss_plat_data *plat_priv; - if (!pci_priv) { - cnss_pr_err("pci_priv is NULL\n"); - return -EINVAL; - } - - plat_priv = pci_priv->plat_priv; if (test_bit(ENABLE_PCI_LINK_DOWN_PANIC, &plat_priv->ctrl_params.quirks)) panic("cnss: PCI link is down\n"); @@ -933,17 +926,40 @@ int cnss_pci_link_down(struct device *dev) if (pci_priv->pci_link_down_ind) { cnss_pr_dbg("PCI link down recovery is in progress, ignore\n"); spin_unlock_irqrestore(&pci_link_down_lock, flags); - return -EINVAL; + return; } pci_priv->pci_link_down_ind = true; spin_unlock_irqrestore(&pci_link_down_lock, flags); reinit_completion(&pci_priv->wake_event); - cnss_pr_err("PCI link down is detected, schedule recovery\n"); - cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN); + if (pci_dev->device == QCA6174_DEVICE_ID) + disable_irq(pci_dev->irq); - return 0; + cnss_fatal_err("PCI link down, schedule recovery\n"); + cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN); +} + +int cnss_pci_link_down(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + int ret; + + if (!pci_priv) { + cnss_pr_err("pci_priv is NULL\n"); + return -EINVAL; + } + + cnss_pr_err("PCI link down is detected by drivers\n"); + + ret = msm_pcie_pm_control(MSM_PCIE_HANDLE_LINKDOWN, + pci_dev->bus->number, pci_dev, NULL, + PM_OPTIONS_DEFAULT); + if (ret) + cnss_pci_handle_linkdown(pci_priv); + + return ret; } EXPORT_SYMBOL(cnss_pci_link_down); @@ -2400,10 +2416,8 @@ static bool cnss_pci_is_drv_supported(struct cnss_pci_data *pci_priv) static void cnss_pci_event_cb(struct msm_pcie_notify *notify) { - unsigned long flags; struct pci_dev *pci_dev; struct cnss_pci_data *pci_priv; - struct cnss_plat_data *plat_priv; if (!notify) return; @@ -2416,27 +2430,9 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify) if (!pci_priv) return; - plat_priv = pci_priv->plat_priv; switch (notify->event) { case MSM_PCIE_EVENT_LINKDOWN: - if (test_bit(ENABLE_PCI_LINK_DOWN_PANIC, - &plat_priv->ctrl_params.quirks)) - panic("cnss: PCI link is down\n"); - - spin_lock_irqsave(&pci_link_down_lock, flags); - if (pci_priv->pci_link_down_ind) { - cnss_pr_dbg("PCI link down recovery is in progress, ignore\n"); - spin_unlock_irqrestore(&pci_link_down_lock, flags); - return; - } - pci_priv->pci_link_down_ind = true; - spin_unlock_irqrestore(&pci_link_down_lock, flags); - - reinit_completion(&pci_priv->wake_event); - cnss_fatal_err("PCI link down, schedule recovery\n"); - if (pci_dev->device == QCA6174_DEVICE_ID) - disable_irq(pci_dev->irq); - cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN); + cnss_pci_handle_linkdown(pci_priv); break; case MSM_PCIE_EVENT_WAKEUP: complete(&pci_priv->wake_event);