cnss2: Add synchronized force wake support

Device is still possible to enter low power state with current
unsync force wake method, and it may cause later failure when
accessing SoC register.

Introduce sync force wake API and expose it to WLAN host driver,
which will ensure device won't enter low power state after
device_wake is asserted.

Change-Id: Iaa7a7bdac910c162600bbf03ac97af83b2f68f3f
Signed-off-by: Lin Bai <lbai@codeaurora.org>
This commit is contained in:
Lin Bai 2020-06-05 12:15:54 +08:00 committed by Gerrit - the friendly Code Review server
parent bbc7f2d3ed
commit 4e43ba3d70
2 changed files with 38 additions and 13 deletions

View File

@ -475,27 +475,22 @@ static int cnss_pci_reg_write(struct cnss_pci_data *pci_priv, u32 offset,
static int cnss_pci_force_wake_get(struct cnss_pci_data *pci_priv)
{
struct device *dev = &pci_priv->pci_dev->dev;
u32 timeout = 0;
int ret;
ret = cnss_pci_force_wake_request(dev);
ret = cnss_pci_force_wake_request_sync(dev,
FORCE_WAKE_DELAY_TIMEOUT_US);
if (ret) {
if (ret != -EAGAIN)
cnss_pr_err("Failed to request force wake\n");
return ret;
}
while (!cnss_pci_is_device_awake(dev) &&
timeout <= FORCE_WAKE_DELAY_TIMEOUT_US) {
usleep_range(FORCE_WAKE_DELAY_MIN_US, FORCE_WAKE_DELAY_MAX_US);
timeout += FORCE_WAKE_DELAY_MAX_US;
}
if (cnss_pci_is_device_awake(dev) != true) {
cnss_pr_err("Timed out to request force wake\n");
cnss_pci_force_wake_release(dev);
return -ETIMEDOUT;
}
/* If device's M1 state-change event races here, it can be ignored,
* as the device is expected to immediately move from M2 to M0
* without entering low power state.
*/
if (cnss_pci_is_device_awake(dev) != true)
cnss_pr_warn("MHI not in M0, while reg still accessible\n");
return 0;
}
@ -2938,6 +2933,35 @@ int cnss_auto_resume(struct device *dev)
}
EXPORT_SYMBOL(cnss_auto_resume);
int cnss_pci_force_wake_request_sync(struct device *dev, int timeout_us)
{
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;
struct mhi_controller *mhi_ctrl;
if (!pci_priv)
return -ENODEV;
if (pci_priv->device_id != QCA6390_DEVICE_ID &&
pci_priv->device_id != QCA6490_DEVICE_ID)
return 0;
mhi_ctrl = pci_priv->mhi_ctrl;
if (!mhi_ctrl)
return -EINVAL;
plat_priv = pci_priv->plat_priv;
if (!plat_priv)
return -ENODEV;
if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
return -EAGAIN;
return mhi_device_get_sync_atomic(mhi_ctrl->mhi_dev, timeout_us);
}
EXPORT_SYMBOL(cnss_pci_force_wake_request_sync);
int cnss_pci_force_wake_request(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);

View File

@ -212,6 +212,7 @@ extern int cnss_wlan_pm_control(struct device *dev, bool vote);
extern int cnss_auto_suspend(struct device *dev);
extern int cnss_auto_resume(struct device *dev);
extern int cnss_pci_is_drv_connected(struct device *dev);
extern int cnss_pci_force_wake_request_sync(struct device *dev, int timeout);
extern int cnss_pci_force_wake_request(struct device *dev);
extern int cnss_pci_is_device_awake(struct device *dev);
extern int cnss_pci_force_wake_release(struct device *dev);