diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 523e472ac0d9..b9450154b6dd 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -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); diff --git a/include/net/cnss2.h b/include/net/cnss2.h index eb37edc647f5..ac786ced79ce 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -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);