mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 14:56:54 -04:00
mt76: mt7921s: fix the device cannot sleep deeply in suspend
According to the MT7921S firmware, the cmd MCU_UNI_CMD_HIF_CTRL have to
be last MCU command to execute in suspend handler and all data traffic
have to be stopped before the cmd MCU_UNI_CMD_HIF_CTRL starts as well
in order that mt7921 can successfully fall into the deep sleep mode.
Where we reuse the flag MT76_STATE_SUSPEND and avoid creating
another global flag to stop all of the traffic onto the SDIO bus.
Fixes: 48fab5bbef ("mt76: mt7921: introduce mt7921s support")
Reported-by: Leon Yen <leon.yen@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
@@ -2432,7 +2432,7 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt76_phy *phy = priv;
|
||||
bool suspend = test_bit(MT76_STATE_SUSPEND, &phy->state);
|
||||
bool suspend = !test_bit(MT76_STATE_RUNNING, &phy->state);
|
||||
struct ieee80211_hw *hw = phy->hw;
|
||||
struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config;
|
||||
int i;
|
||||
|
||||
@@ -1258,8 +1258,6 @@ static int mt7921_suspend(struct ieee80211_hw *hw,
|
||||
mt7921_mutex_acquire(dev);
|
||||
|
||||
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
|
||||
set_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
|
||||
ieee80211_iterate_active_interfaces(hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt76_connac_mcu_set_suspend_iter,
|
||||
@@ -1278,7 +1276,6 @@ static int mt7921_resume(struct ieee80211_hw *hw)
|
||||
mt7921_mutex_acquire(dev);
|
||||
|
||||
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
|
||||
ieee80211_iterate_active_interfaces(hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt76_connac_mcu_set_suspend_iter,
|
||||
|
||||
@@ -206,6 +206,8 @@ static int mt7921s_suspend(struct device *__dev)
|
||||
int err;
|
||||
|
||||
pm->suspended = true;
|
||||
set_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
|
||||
|
||||
cancel_delayed_work_sync(&pm->ps_work);
|
||||
cancel_work_sync(&pm->wake_work);
|
||||
|
||||
@@ -213,10 +215,6 @@ static int mt7921s_suspend(struct device *__dev)
|
||||
if (err < 0)
|
||||
goto restore_suspend;
|
||||
|
||||
err = mt76_connac_mcu_set_hif_suspend(mdev, true);
|
||||
if (err)
|
||||
goto restore_suspend;
|
||||
|
||||
/* always enable deep sleep during suspend to reduce
|
||||
* power consumption
|
||||
*/
|
||||
@@ -224,34 +222,45 @@ static int mt7921s_suspend(struct device *__dev)
|
||||
|
||||
mt76_txq_schedule_all(&dev->mphy);
|
||||
mt76_worker_disable(&mdev->tx_worker);
|
||||
mt76_worker_disable(&mdev->sdio.txrx_worker);
|
||||
mt76_worker_disable(&mdev->sdio.status_worker);
|
||||
mt76_worker_disable(&mdev->sdio.net_worker);
|
||||
cancel_work_sync(&mdev->sdio.stat_work);
|
||||
clear_bit(MT76_READING_STATS, &dev->mphy.state);
|
||||
|
||||
mt76_tx_status_check(mdev, true);
|
||||
|
||||
mt76_worker_schedule(&mdev->sdio.txrx_worker);
|
||||
wait_event_timeout(dev->mt76.sdio.wait,
|
||||
mt76s_txqs_empty(&dev->mt76), 5 * HZ);
|
||||
|
||||
/* It is supposed that SDIO bus is idle at the point */
|
||||
err = mt76_connac_mcu_set_hif_suspend(mdev, true);
|
||||
if (err)
|
||||
goto restore_worker;
|
||||
|
||||
mt76_worker_disable(&mdev->sdio.txrx_worker);
|
||||
mt76_worker_disable(&mdev->sdio.net_worker);
|
||||
|
||||
err = mt7921_mcu_fw_pmctrl(dev);
|
||||
if (err)
|
||||
goto restore_worker;
|
||||
goto restore_txrx_worker;
|
||||
|
||||
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
|
||||
return 0;
|
||||
|
||||
restore_txrx_worker:
|
||||
mt76_worker_enable(&mdev->sdio.net_worker);
|
||||
mt76_worker_enable(&mdev->sdio.txrx_worker);
|
||||
mt76_connac_mcu_set_hif_suspend(mdev, false);
|
||||
|
||||
restore_worker:
|
||||
mt76_worker_enable(&mdev->tx_worker);
|
||||
mt76_worker_enable(&mdev->sdio.txrx_worker);
|
||||
mt76_worker_enable(&mdev->sdio.status_worker);
|
||||
mt76_worker_enable(&mdev->sdio.net_worker);
|
||||
|
||||
if (!pm->ds_enable)
|
||||
mt76_connac_mcu_set_deep_sleep(mdev, false);
|
||||
|
||||
mt76_connac_mcu_set_hif_suspend(mdev, false);
|
||||
|
||||
restore_suspend:
|
||||
clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
|
||||
pm->suspended = false;
|
||||
|
||||
return err;
|
||||
@@ -266,6 +275,7 @@ static int mt7921s_resume(struct device *__dev)
|
||||
int err;
|
||||
|
||||
pm->suspended = false;
|
||||
clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
|
||||
|
||||
err = mt7921_mcu_drv_pmctrl(dev);
|
||||
if (err < 0)
|
||||
|
||||
@@ -479,7 +479,8 @@ static void mt76s_status_worker(struct mt76_worker *w)
|
||||
resched = true;
|
||||
|
||||
if (dev->drv->tx_status_data &&
|
||||
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
|
||||
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state) &&
|
||||
!test_bit(MT76_STATE_SUSPEND, &dev->phy.state))
|
||||
queue_work(dev->wq, &dev->sdio.stat_work);
|
||||
} while (nframes > 0);
|
||||
|
||||
|
||||
@@ -317,7 +317,8 @@ void mt76s_txrx_worker(struct mt76_sdio *sdio)
|
||||
if (ret > 0)
|
||||
nframes += ret;
|
||||
|
||||
if (test_bit(MT76_MCU_RESET, &dev->phy.state)) {
|
||||
if (test_bit(MT76_MCU_RESET, &dev->phy.state) ||
|
||||
test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) {
|
||||
if (!mt76s_txqs_empty(dev))
|
||||
continue;
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user