]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mt76: mt7915: fix list corruption after hardware restart
authorFelix Fietkau <nbd@nbd.name>
Wed, 27 Aug 2025 08:53:50 +0000 (10:53 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Sep 2025 17:02:19 +0000 (19:02 +0200)
[ Upstream commit 065c79df595af21d6d1b27d642860faa1d938774 ]

Since stations are recreated from scratch, all lists that wcids are added
to must be cleared before calling ieee80211_restart_hw.
Set wcid->sta = 0 for each wcid entry in order to ensure that they are
not added again before they are ready.

Fixes: 8a55712d124f ("wifi: mt76: mt7915: enable full system reset support")
Link: https://patch.msgid.link/20250827085352.51636-4-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/mediatek/mt76/mac80211.c
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/mt7915/mac.c

index 45c8db939d554671d68f1914f5febb5f5a2af752..4e435bec828b5448b3338cf45afb6af4f4624436 100644 (file)
@@ -818,6 +818,43 @@ void mt76_free_device(struct mt76_dev *dev)
 }
 EXPORT_SYMBOL_GPL(mt76_free_device);
 
+static void mt76_reset_phy(struct mt76_phy *phy)
+{
+       if (!phy)
+               return;
+
+       INIT_LIST_HEAD(&phy->tx_list);
+}
+
+void mt76_reset_device(struct mt76_dev *dev)
+{
+       int i;
+
+       rcu_read_lock();
+       for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
+               struct mt76_wcid *wcid;
+
+               wcid = rcu_dereference(dev->wcid[i]);
+               if (!wcid)
+                       continue;
+
+               wcid->sta = 0;
+               mt76_wcid_cleanup(dev, wcid);
+               rcu_assign_pointer(dev->wcid[i], NULL);
+       }
+       rcu_read_unlock();
+
+       INIT_LIST_HEAD(&dev->wcid_list);
+       INIT_LIST_HEAD(&dev->sta_poll_list);
+       dev->vif_mask = 0;
+       memset(dev->wcid_mask, 0, sizeof(dev->wcid_mask));
+
+       mt76_reset_phy(&dev->phy);
+       for (i = 0; i < ARRAY_SIZE(dev->phys); i++)
+               mt76_reset_phy(dev->phys[i]);
+}
+EXPORT_SYMBOL_GPL(mt76_reset_device);
+
 struct mt76_phy *mt76_vif_phy(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif)
 {
index 0ecf77fcbe3d07ade874e95f1c03afbd4ff986b2..0290ddbb2424e632cb366782d0224cbfc40ce5e7 100644 (file)
@@ -1241,6 +1241,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
                         struct ieee80211_rate *rates, int n_rates);
 void mt76_unregister_device(struct mt76_dev *dev);
 void mt76_free_device(struct mt76_dev *dev);
+void mt76_reset_device(struct mt76_dev *dev);
 void mt76_unregister_phy(struct mt76_phy *phy);
 
 struct mt76_phy *mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size,
index 6639976afcee6a8d0b3eee9e07e6eb8a334bf845..1c0d310146d63bc39357d604b549c83e37c8da35 100644 (file)
@@ -1460,17 +1460,15 @@ mt7915_mac_full_reset(struct mt7915_dev *dev)
        if (i == 10)
                dev_err(dev->mt76.dev, "chip full reset failed\n");
 
-       spin_lock_bh(&dev->mt76.sta_poll_lock);
-       while (!list_empty(&dev->mt76.sta_poll_list))
-               list_del_init(dev->mt76.sta_poll_list.next);
-       spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
-       memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask));
-       dev->mt76.vif_mask = 0;
        dev->phy.omac_mask = 0;
        if (phy2)
                phy2->omac_mask = 0;
 
+       mt76_reset_device(&dev->mt76);
+
+       INIT_LIST_HEAD(&dev->sta_rc_list);
+       INIT_LIST_HEAD(&dev->twt_list);
+
        i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
        dev->mt76.global_wcid.idx = i;
        dev->recovery.hw_full_reset = false;