From 70d7837d2dd3eeed89f8ce25ce42d55ccb504797 Mon Sep 17 00:00:00 2001 From: Kai Liu Date: Fri, 8 Jan 2021 19:32:48 +0800 Subject: [PATCH] cnss2: retry mhi suspend in case packets are pending in MHI layer Platform driver sends QMI message to get device status, after it receives response, it will suspend device, but at that time QRTR might been sending some flow control packets, so mhi layer will reject suspend because packets are still pending, platform driver retry suspend to cover this corner case. Change-Id: I1c2e4a490e525199929095579cc6c6e975f88736 Signed-off-by: Kai Liu --- drivers/net/wireless/cnss2/pci.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) 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; }