]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mt76: mt7921e: fix race issue between reset and suspend/resume
authorSean Wang <sean.wang@mediatek.com>
Wed, 20 Jul 2022 22:25:37 +0000 (06:25 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Oct 2022 07:57:09 +0000 (09:57 +0200)
[ Upstream commit ff6c4a6449793e9718ef2e9ad46864b63022648e ]

It is unexpected that the reset work is running simultaneously with
the suspend or resume context and it is possible that reset work is still
running even after mt7921 is suspended if we don't fix the race issue.

Thus, the suspend procedure should be waiting until the reset is completed
at the beginning and ignore the subsequent the reset requests.

In case there is an error that happens during either suspend or resume
handler, we will schedule a reset task to recover the error before
returning the error code to ensure we can immediately fix the error there.

Fixes: 0c1ce9884607 ("mt76: mt7921: add wifi reset support")
Co-developed-by: YN Chen <YN.Chen@mediatek.com>
Signed-off-by: YN Chen <YN.Chen@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/mediatek/mt76/mt7921/mac.c
drivers/net/wireless/mediatek/mt76/mt7921/pci.c

index 2a2ea7b9977a46c990f9bbe572f16e9c82c6a0c8..7e0cddc2aeab5ad2b0574110f4c3d5f5d7d44eda 100644 (file)
@@ -1215,6 +1215,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
 void mt7921_reset(struct mt76_dev *mdev)
 {
        struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+       struct mt76_connac_pm *pm = &dev->pm;
 
        if (!dev->hw_init_done)
                return;
@@ -1222,8 +1223,12 @@ void mt7921_reset(struct mt76_dev *mdev)
        if (dev->hw_full_reset)
                return;
 
+       if (pm->suspended)
+               return;
+
        queue_work(dev->mt76.wq, &dev->reset_work);
 }
+EXPORT_SYMBOL_GPL(mt7921_reset);
 
 void mt7921_mac_update_mib_stats(struct mt7921_phy *phy)
 {
index b5fb22b8e0869d65388f5f0b7cf318930e15ce32..295c21586273ee1cb41c7e5e4ed5c398f85f304e 100644 (file)
@@ -368,6 +368,7 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        int i, err;
 
        pm->suspended = true;
+       flush_work(&dev->reset_work);
        cancel_delayed_work_sync(&pm->ps_work);
        cancel_work_sync(&pm->wake_work);
 
@@ -433,6 +434,9 @@ restore_napi:
 restore_suspend:
        pm->suspended = false;
 
+       if (err < 0)
+               mt7921_reset(&dev->mt76);
+
        return err;
 }
 
@@ -451,7 +455,7 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
 
        err = mt7921_mcu_drv_pmctrl(dev);
        if (err < 0)
-               return err;
+               goto failed;
 
        mt7921_wpdma_reinit_cond(dev);
 
@@ -481,11 +485,12 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
                mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
 
        err = mt76_connac_mcu_set_hif_suspend(mdev, false);
-       if (err)
-               return err;
-
+failed:
        pm->suspended = false;
 
+       if (err < 0)
+               mt7921_reset(&dev->mt76);
+
        return err;
 }
 #endif /* CONFIG_PM */