diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 3e0102e14b2c..859590bac5b7 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include #include @@ -83,6 +83,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 }, @@ -1359,6 +1361,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; @@ -1401,10 +1404,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: @@ -1433,8 +1447,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; }