]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7996: Use deflink for AMPDU rx reordering
authorLorenzo Bianconi <lorenzo@kernel.org>
Sat, 23 Aug 2025 14:55:37 +0000 (16:55 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 15 Sep 2025 07:47:39 +0000 (09:47 +0200)
Packets belonging to the same TID can be sent over multiple links.
AMPDU rx reordering must be performed over all active links. Fix the
problem always using default link for AMPDU rx reordering.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250823-mt7996-mlo-aggr-fix-v1-1-f35cf0ea4c8a@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/agg-rx.c
drivers/net/wireless/mediatek/mt76/mt7996/mac.c
drivers/net/wireless/mediatek/mt76/mt7996/main.c
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h

index 07c386c7b4d08967f5dcb69ee9282b042afbce10..936ab1ca92460793f4d275ad18dd6f7722445d90 100644 (file)
@@ -173,6 +173,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
        if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
                return;
 
+       if (wcid->def_wcid)
+               wcid = wcid->def_wcid;
        tid = rcu_dereference(wcid->aggr[tidno]);
        if (!tid)
                return;
index b3fcca9bbb95899ee6f994cfdf293da7889ab0ae..78f4c48c361723c4ccb0a612556efe50668b765e 100644 (file)
@@ -1183,8 +1183,14 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
        txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
        if (link_sta) {
                wcid_idx = wcid->idx;
-               if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
-                       mt7996_tx_check_aggr(link_sta, wcid, t->skb);
+               if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) {
+                       struct mt7996_sta *msta;
+
+                       /* AMPDU state is stored in the primary link */
+                       msta = (void *)link_sta->sta->drv_priv;
+                       mt7996_tx_check_aggr(link_sta, &msta->deflink.wcid,
+                                            t->skb);
+               }
        } else {
                wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);
        }
index dd951e2ed4030394df758bcee1a6197cc22d05bd..8a90fee6e8b3c01f0b665540d1db4317ddb3866f 100644 (file)
@@ -990,11 +990,6 @@ static void
 mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
                           struct mt7996_sta_link *msta_link)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(msta_link->wcid.aggr); i++)
-               mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, i);
-
        mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
                               MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
 
@@ -1369,16 +1364,13 @@ static int
 mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                    struct ieee80211_ampdu_params *params)
 {
-       enum ieee80211_ampdu_mlme_action action = params->action;
        struct mt7996_dev *dev = mt7996_hw_dev(hw);
        struct ieee80211_sta *sta = params->sta;
        struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
        struct ieee80211_txq *txq = sta->txq[params->tid];
-       struct ieee80211_link_sta *link_sta;
        u16 tid = params->tid;
        u16 ssn = params->ssn;
        struct mt76_txq *mtxq;
-       unsigned int link_id;
        int ret = 0;
 
        if (!txq)
@@ -1388,61 +1380,42 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
        mutex_lock(&dev->mt76.mutex);
 
-       for_each_sta_active_link(vif, sta, link_sta, link_id) {
-               struct mt7996_sta_link *msta_link;
-               struct mt7996_vif_link *link;
-
-               msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
-               if (!msta_link)
-                       continue;
-
-               link = mt7996_vif_link(dev, vif, link_id);
-               if (!link)
-                       continue;
-
-               switch (action) {
-               case IEEE80211_AMPDU_RX_START:
-                       mt76_rx_aggr_start(&dev->mt76, &msta_link->wcid, tid,
-                                          ssn, params->buf_size);
-                       ret = mt7996_mcu_add_rx_ba(dev, params, link,
-                                                  msta_link, true);
-                       break;
-               case IEEE80211_AMPDU_RX_STOP:
-                       mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, tid);
-                       ret = mt7996_mcu_add_rx_ba(dev, params, link,
-                                                  msta_link, false);
-                       break;
-               case IEEE80211_AMPDU_TX_OPERATIONAL:
-                       mtxq->aggr = true;
-                       mtxq->send_bar = false;
-                       ret = mt7996_mcu_add_tx_ba(dev, params, link,
-                                                  msta_link, true);
-                       break;
-               case IEEE80211_AMPDU_TX_STOP_FLUSH:
-               case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
-                       mtxq->aggr = false;
-                       clear_bit(tid, &msta_link->wcid.ampdu_state);
-                       ret = mt7996_mcu_add_tx_ba(dev, params, link,
-                                                  msta_link, false);
-                       break;
-               case IEEE80211_AMPDU_TX_START:
-                       set_bit(tid, &msta_link->wcid.ampdu_state);
-                       ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
-                       break;
-               case IEEE80211_AMPDU_TX_STOP_CONT:
-                       mtxq->aggr = false;
-                       clear_bit(tid, &msta_link->wcid.ampdu_state);
-                       ret = mt7996_mcu_add_tx_ba(dev, params, link,
-                                                  msta_link, false);
-                       break;
-               }
-
-               if (ret)
-                       break;
-       }
-
-       if (action == IEEE80211_AMPDU_TX_STOP_CONT)
+       switch (params->action) {
+       case IEEE80211_AMPDU_RX_START:
+               /* Since packets belonging to the same TID can be split over
+                * multiple links, store the AMPDU state for reordering in the
+                * primary link
+                */
+               mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid,
+                                  ssn, params->buf_size);
+               ret = mt7996_mcu_add_rx_ba(dev, params, vif, true);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid);
+               ret = mt7996_mcu_add_rx_ba(dev, params, vif, false);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               mtxq->aggr = true;
+               mtxq->send_bar = false;
+               ret = mt7996_mcu_add_tx_ba(dev, params, vif, true);
+               break;
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+               mtxq->aggr = false;
+               clear_bit(tid, &msta->deflink.wcid.ampdu_state);
+               ret = mt7996_mcu_add_tx_ba(dev, params, vif, false);
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               set_bit(tid, &msta->deflink.wcid.ampdu_state);
+               ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
+               break;
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+               mtxq->aggr = false;
+               clear_bit(tid, &msta->deflink.wcid.ampdu_state);
+               ret = mt7996_mcu_add_tx_ba(dev, params, vif, false);
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       }
 
        mutex_unlock(&dev->mt76.mutex);
 
index aad58f7831c7b2c62f2185c0010640a03479b599..d63978b4c3d26a95ca586b53e4215d81be2f3b31 100644 (file)
@@ -1192,23 +1192,67 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif,
 /** starec & wtbl **/
 int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
                         struct ieee80211_ampdu_params *params,
-                        struct mt7996_vif_link *link,
-                        struct mt7996_sta_link *msta_link, bool enable)
+                        struct ieee80211_vif *vif, bool enable)
 {
-       if (enable && !params->amsdu)
-               msta_link->wcid.amsdu = false;
+       struct ieee80211_sta *sta = params->sta;
+       struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+       struct ieee80211_link_sta *link_sta;
+       unsigned int link_id;
+       int ret = 0;
+
+       for_each_sta_active_link(vif, sta, link_sta, link_id) {
+               struct mt7996_sta_link *msta_link;
+               struct mt7996_vif_link *link;
+
+               msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+               if (!msta_link)
+                       continue;
 
-       return mt7996_mcu_sta_ba(dev, &link->mt76, params, &msta_link->wcid,
-                                enable, true);
+               link = mt7996_vif_link(dev, vif, link_id);
+               if (!link)
+                       continue;
+
+               if (enable && !params->amsdu)
+                       msta_link->wcid.amsdu = false;
+
+               ret = mt7996_mcu_sta_ba(dev, &link->mt76, params,
+                                       &msta_link->wcid, enable, true);
+               if (ret)
+                       break;
+       }
+
+       return ret;
 }
 
 int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
                         struct ieee80211_ampdu_params *params,
-                        struct mt7996_vif_link *link,
-                        struct mt7996_sta_link *msta_link, bool enable)
+                        struct ieee80211_vif *vif, bool enable)
 {
-       return mt7996_mcu_sta_ba(dev, &link->mt76, params, &msta_link->wcid,
-                                enable, false);
+       struct ieee80211_sta *sta = params->sta;
+       struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+       struct ieee80211_link_sta *link_sta;
+       unsigned int link_id;
+       int ret = 0;
+
+       for_each_sta_active_link(vif, sta, link_sta, link_id) {
+               struct mt7996_sta_link *msta_link;
+               struct mt7996_vif_link *link;
+
+               msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+               if (!msta_link)
+                       continue;
+
+               link = mt7996_vif_link(dev, vif, link_id);
+               if (!link)
+                       continue;
+
+               ret = mt7996_mcu_sta_ba(dev, &link->mt76, params,
+                                       &msta_link->wcid, enable, false);
+               if (ret)
+                       break;
+       }
+
+       return ret;
 }
 
 static void
index b98cfe6e5be8c6b77357cf7d2a76135f10609ca4..97b84710667ffdb5b6188a72d6f8475f7eb9a128 100644 (file)
@@ -612,12 +612,10 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
                                struct mt7996_sta_link *msta_link);
 int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
                         struct ieee80211_ampdu_params *params,
-                        struct mt7996_vif_link *link,
-                        struct mt7996_sta_link *msta_link, bool enable);
+                        struct ieee80211_vif *vif, bool enable);
 int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
                         struct ieee80211_ampdu_params *params,
-                        struct mt7996_vif_link *link,
-                        struct mt7996_sta_link *msta_link, bool enable);
+                        struct ieee80211_vif *vif, bool enable);
 int mt7996_mcu_update_bss_color(struct mt7996_dev *dev,
                                struct mt76_vif_link *mlink,
                                struct cfg80211_he_bss_color *he_bss_color);