diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 2a981008cc3e..4a75672dc425 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -84,6 +84,8 @@ static DEFINE_SPINLOCK(time_sync_lock); #define HST_HANG_DATA_OFFSET ((3 * 1024 * 1024) - HANG_DATA_LENGTH) #define HSP_HANG_DATA_OFFSET ((2 * 1024 * 1024) - HANG_DATA_LENGTH) +#define MHI_SUSPEND_RETRY_CNT 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 }, @@ -1364,6 +1366,7 @@ static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, enum cnss_mhi_state mhi_state) { int ret = 0; + u8 retry = 0; if (pci_priv->device_id == QCA6174_DEVICE_ID) return 0; @@ -1406,10 +1409,21 @@ static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, break; case CNSS_MHI_SUSPEND: mutex_lock(&pci_priv->mhi_ctrl->pm_mutex); - if (pci_priv->drv_connected_last) + if (pci_priv->drv_connected_last) { ret = mhi_pm_fast_suspend(pci_priv->mhi_ctrl, true); - else + } else { ret = mhi_pm_suspend(pci_priv->mhi_ctrl); + /* in some corner case, when cnss try to suspend, + * there is still packets pending in mhi layer, + * so retry suspend to save roll back effort. + */ + while (ret == -EBUSY && retry < MHI_SUSPEND_RETRY_CNT) { + usleep_range(5000, 6000); + retry++; + cnss_pr_err("mhi is busy, retry #%u", retry); + ret = mhi_pm_suspend(pci_priv->mhi_ctrl); + } + } mutex_unlock(&pci_priv->mhi_ctrl->pm_mutex); break; case CNSS_MHI_RESUME: @@ -1441,8 +1455,8 @@ static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, return 0; out: - cnss_pr_err("Failed to set MHI state: %s(%d)\n", - cnss_mhi_state_to_str(mhi_state), mhi_state); + cnss_pr_err("Failed to set MHI state: %s(%d), ret %d\n", + cnss_mhi_state_to_str(mhi_state), mhi_state, ret); return ret; }