wifi: mt76: mt7996: use correct link_id when filling TXD and TXP

Obtain the correct link ID and, if needed, switch to the corresponding
wcid before populating the TX descriptor and TX payload.

Rules for link id:
- For QoS data of MLD peers (excluding EAPOL), select the primary or
  secondary wcid based on whether the TID is odd or even to meet FW/HW
  requirements
- For other packets, use IEEE80211_TX_CTRL_MLO_LINK if specified
  (such as multicast and broadcast packets)

Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20251106064203.1000505-8-shayne.chen@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Shayne Chen 2025-11-06 14:41:59 +08:00 committed by Felix Fietkau
parent 7eaea3a8ba
commit 85cd5534a3
4 changed files with 42 additions and 6 deletions

View File

@ -1035,15 +1035,20 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_vif *vif = info->control.vif;
struct mt7996_vif *mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL;
struct mt76_vif_link *mlink = NULL;
struct mt76_txwi_cache *t;
int id, i, pid, nbuf = tx_info->nbuf - 1;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
__le32 *ptr = (__le32 *)txwi_ptr;
u8 *txwi = (u8 *)txwi_ptr;
u8 link_id;
if (unlikely(tx_info->skb->len <= ETH_HLEN))
return -EINVAL;
@ -1051,6 +1056,30 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;
if ((is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo &&
likely(tx_info->skb->protocol != cpu_to_be16(ETH_P_PAE))) {
u8 tid = tx_info->skb->priority & IEEE80211_QOS_CTL_TID_MASK;
link_id = (tid % 2) ? msta->seclink_id : msta->deflink_id;
} else {
link_id = u32_get_bits(info->control.flags,
IEEE80211_TX_CTRL_MLO_LINK);
}
if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) {
if (msta) {
struct mt7996_sta_link *msta_link =
rcu_dereference(msta->link[link_id]);
if (msta_link)
wcid = &msta_link->wcid;
} else if (mvif) {
mlink = rcu_dereference(mvif->mt76.link[link_id]);
if (mlink && mlink->wcid)
wcid = mlink->wcid;
}
}
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
t->skb = tx_info->skb;
@ -1155,10 +1184,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb))
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
if (vif) {
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt76_vif_link *mlink = NULL;
if (mvif) {
if (wcid->offchannel)
mlink = rcu_dereference(mvif->mt76.offchannel_link);
if (!mlink)

View File

@ -963,6 +963,7 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
msta_link = &msta->deflink;
msta->deflink_id = link_id;
msta->seclink_id = msta->deflink_id;
for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
struct mt76_txq *mtxq;
@ -977,6 +978,11 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
msta_link = kzalloc(sizeof(*msta_link), GFP_KERNEL);
if (!msta_link)
return -ENOMEM;
if (msta->seclink_id == msta->deflink_id &&
(sta->valid_links & ~BIT(msta->deflink_id)))
msta->seclink_id = __ffs(sta->valid_links &
~BIT(msta->deflink_id));
}
INIT_LIST_HEAD(&msta_link->rc_list);
@ -1051,6 +1057,8 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
if (msta->deflink_id == link_id) {
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
continue;
} else if (msta->seclink_id == link_id) {
msta->seclink_id = IEEE80211_LINK_UNSPECIFIED;
}
kfree_rcu(msta_link, rcu_head);
@ -1146,6 +1154,7 @@ mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mutex_lock(&dev->mt76.mutex);
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
msta->seclink_id = IEEE80211_LINK_UNSPECIFIED;
msta->vif = mvif;
err = mt7996_mac_sta_add_links(dev, vif, sta, links);

View File

@ -2394,8 +2394,8 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
if (nlinks > 1) {
link_id = __ffs(sta->valid_links & ~BIT(msta->deflink_id));
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
msta_link = mt76_dereference(msta->link[msta->seclink_id],
&dev->mt76);
if (!msta_link)
return;
}

View File

@ -243,6 +243,7 @@ struct mt7996_sta {
struct mt7996_sta_link deflink; /* must be first */
struct mt7996_sta_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
u8 deflink_id;
u8 seclink_id;
struct mt7996_vif *vif;
};