wifi: mt76: mt7921s: fix potential hung tasks during chip recovery
authorLeon Yen <leon.yen@mediatek.com>
Thu, 7 Mar 2024 09:46:32 +0000 (17:46 +0800)
committerFelix Fietkau <nbd@nbd.name>
Thu, 2 May 2024 10:44:51 +0000 (12:44 +0200)
During chip recovery (e.g. chip reset), there is a possible situation that
kernel worker reset_work is holding the lock and waiting for kernel thread
stat_worker to be parked, while stat_worker is waiting for the release of
the same lock.
It causes a deadlock resulting in the dumping of hung tasks messages and
possible rebooting of the device.

This patch prevents the execution of stat_worker during the chip recovery.

Signed-off-by: Leon Yen <leon.yen@mediatek.com>
Signed-off-by: Ming Yen Hsieh <MingYen.Hsieh@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7921/mac.c
drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
drivers/net/wireless/mediatek/mt76/sdio.c

index 867e14f6b93a0679079c57f463b8a9b7fc2c7c95..73e42ef429837c02475c5b5f69ca4676ac359ef6 100644 (file)
@@ -663,6 +663,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
        int i, ret;
 
        dev_dbg(dev->mt76.dev, "chip reset\n");
+       set_bit(MT76_RESET, &dev->mphy.state);
        dev->hw_full_reset = true;
        ieee80211_stop_queues(hw);
 
@@ -691,6 +692,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
        }
 
        dev->hw_full_reset = false;
+       clear_bit(MT76_RESET, &dev->mphy.state);
        pm->suspended = false;
        ieee80211_wake_queues(hw);
        ieee80211_iterate_active_interfaces(hw,
index c866144ff06137de958c080c2209389895520375..031ba9aaa4e2f8fcdb83fa97feaf9b9bc1947e76 100644 (file)
@@ -64,7 +64,6 @@ int mt7921e_mac_reset(struct mt792x_dev *dev)
        mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
        mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
 
-       set_bit(MT76_RESET, &dev->mphy.state);
        set_bit(MT76_MCU_RESET, &dev->mphy.state);
        wake_up(&dev->mt76.mcu.wait);
        skb_queue_purge(&dev->mt76.mcu.res_q);
@@ -115,7 +114,6 @@ int mt7921e_mac_reset(struct mt792x_dev *dev)
 
        err = __mt7921_start(&dev->phy);
 out:
-       clear_bit(MT76_RESET, &dev->mphy.state);
 
        local_bh_disable();
        napi_enable(&dev->mt76.tx_napi);
index 389eb0903807e9603d99830f61aef8f7cce5c598..1f77cf71ca701a65b2f02e060d8c39963fcb705a 100644 (file)
@@ -98,7 +98,6 @@ int mt7921s_mac_reset(struct mt792x_dev *dev)
        mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
        mt76_txq_schedule_all(&dev->mphy);
        mt76_worker_disable(&dev->mt76.tx_worker);
-       set_bit(MT76_RESET, &dev->mphy.state);
        set_bit(MT76_MCU_RESET, &dev->mphy.state);
        wake_up(&dev->mt76.mcu.wait);
        skb_queue_purge(&dev->mt76.mcu.res_q);
@@ -135,7 +134,6 @@ int mt7921s_mac_reset(struct mt792x_dev *dev)
 
        err = __mt7921_start(&dev->phy);
 out:
-       clear_bit(MT76_RESET, &dev->mphy.state);
 
        mt76_worker_enable(&dev->mt76.tx_worker);
 
index 593246b555183681f10d6778e5ae6b17aca6be95..1ca5438b695835cd4cd0f83d50edaea17ac8b915 100644 (file)
@@ -499,7 +499,8 @@ static void mt76s_tx_status_data(struct mt76_worker *worker)
        dev = container_of(sdio, struct mt76_dev, sdio);
 
        while (true) {
-               if (test_bit(MT76_REMOVED, &dev->phy.state))
+               if (test_bit(MT76_RESET, &dev->phy.state) ||
+                   test_bit(MT76_REMOVED, &dev->phy.state))
                        break;
 
                if (!dev->drv->tx_status_data(dev, &update))