wifi: mt76: mt7996: fix MLD ID in MAC TXD and HIF TXP

Problem:
MCU command timeout while the firmware state is normal, and the
firmware keeps showing the error log "ERROR!! NO PAUSE...".

Root cause:
If the MLD_ID field in the TXD is neither the primary link id nor the
secondary link id, it may lead to a firmware busy loop when the third
link is in power saving mode.

Remap frames directed to a third link to the primary link wcid. Since
TX status events and txfree completions carry the wcid the firmware
saw, use the remapped wcid for packet id tracking and non-AQL packet
accounting as well, while the frame keeps its original link context
for addressing, band and OMAC selection.

Fixes: 85cd5534a3f2 ("wifi: mt76: mt7996: use correct link_id when filling TXD and TXP")
Signed-off-by: Peter Chiu <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Peter Chiu
2026-07-22 10:51:04 +02:00
committed by Felix Fietkau
parent b05c7c1df2
commit 4efe882252
3 changed files with 31 additions and 1 deletions
+29
View File
@@ -854,6 +854,33 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT);
}
/* The WLAN_IDX in the TXD and TXP must belong to the primary or secondary
* link of an MLD station; any other link id can make the firmware spin when
* that link is in powersave. Completion events carry the same index, so the
* wcid used for status tracking and accounting must match it
*/
struct mt76_wcid *mt7996_get_tx_wcid(struct mt76_wcid *wcid)
{
struct mt7996_sta_link *msta_link;
struct mt7996_sta *msta;
if (!wcid->sta)
return wcid;
msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
msta = msta_link->sta;
if (!msta || wcid->link_id == msta->seclink_id ||
wcid->link_id == msta->deflink_id)
return wcid;
msta_link = mt7996_sta_link(msta, msta->deflink_id);
if (msta_link)
return &msta_link->wcid;
return wcid;
}
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
@@ -1091,6 +1118,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
tx_info->buf[1].len, DMA_TO_DEVICE);
}
wcid = mt7996_get_tx_wcid(wcid);
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
memset(txwi_ptr, 0, MT_TXD_SIZE);
/* Transmit non qos data by 802.11 header and need to fill txd by host*/
+1 -1
View File
@@ -1578,7 +1578,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
if (msta_link)
wcid = &msta_link->wcid;
}
mt76_tx(mphy, control->sta, wcid, skb);
mt76_tx(mphy, control->sta, mt7996_get_tx_wcid(wcid), skb);
unlock:
rcu_read_unlock();
}
+1
View File
@@ -926,6 +926,7 @@ bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
void mt7996_mac_reset_counters(struct mt7996_phy *phy);
void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
struct mt76_wcid *mt7996_get_tx_wcid(struct mt76_wcid *wcid);
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,