blob: c1eda8bab10f0520057f53e6fa627d58390e0bf4 [file] [log] [blame]
developer66e89bc2024-04-23 14:50:01 +08001From 9bff2b264652d23bf0dc056f1e76120951c8d833 Mon Sep 17 00:00:00 2001
2From: Shayne Chen <shayne.chen@mediatek.com>
3Date: Wed, 29 Nov 2023 10:12:39 +0800
4Subject: [PATCH 091/116] wifi: mt76: mt7996: support multi-link sta links and
5 MLO sta callbacks
6
7Rework add_sta functions to add_link_sta functions, and support
8.change_sta_links callback.
9This is a preliminary patch to add MLO support for mt7996 chipsets.
10
11Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
12Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
13Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
14---
15 mt76_connac_mcu.h | 2 +
16 mt7996/main.c | 309 ++++++++++++++++++++++++++++++++++++----------
17 mt7996/mcu.c | 117 ++++++++++++++++++
18 mt7996/mcu.h | 29 +++++
19 mt7996/mt7996.h | 7 ++
20 5 files changed, 398 insertions(+), 66 deletions(-)
21
22diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
23index f7da63658..d45765beb 100644
24--- a/mt76_connac_mcu.h
25+++ b/mt76_connac_mcu.h
26@@ -814,7 +814,9 @@ enum {
27 STA_REC_HE_6G = 0x17,
28 STA_REC_HE_V2 = 0x19,
29 STA_REC_MLD = 0x20,
30+ STA_REC_EHT_MLD = 0x21,
31 STA_REC_EHT = 0x22,
32+ STA_REC_MLD_TEARDOWN = 0x23,
33 STA_REC_PN_INFO = 0x26,
34 STA_REC_KEY_V3 = 0x27,
35 STA_REC_HDRT = 0x28,
36diff --git a/mt7996/main.c b/mt7996/main.c
37index 38aae12be..b193e638e 100644
38--- a/mt7996/main.c
39+++ b/mt7996/main.c
40@@ -928,42 +928,234 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
41 mutex_unlock(&dev->mt76.mutex);
42 }
43
44+static void mt7996_remove_link_sta(struct mt7996_dev *dev,
45+ struct ieee80211_bss_conf *conf,
46+ struct mt7996_bss_conf *mconf,
47+ struct ieee80211_link_sta *link_sta,
48+ struct mt7996_link_sta *mlink)
49+{
50+ struct ieee80211_sta *sta = link_sta->sta;
51+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
52+ int i;
53+
54+ if (!mlink)
55+ return;
56+
57+ for (i = 0; i < ARRAY_SIZE(mlink->wcid.aggr); i++)
58+ mt76_rx_aggr_stop(&dev->mt76, &mlink->wcid, i);
59+
60+ if (sta->mlo)
61+ mt7996_mcu_teardown_mld_sta(dev, mconf, mlink);
62+ else
63+ mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
64+
65+ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
66+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
67+
68+ for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
69+ mt7996_mac_twt_teardown_flow(dev, mlink, i);
70+
71+ rcu_assign_pointer(mlink->sta->link[mlink->wcid.link_id], NULL);
72+
73+ spin_lock_bh(&dev->mt76.sta_poll_lock);
74+ if (!list_empty(&mlink->wcid.poll_list))
75+ list_del_init(&mlink->wcid.poll_list);
76+ if (!list_empty(&mlink->rc_list))
77+ list_del_init(&mlink->rc_list);
78+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
79+
80+ /* TODO: update primary link */
81+ if (sta->valid_links) {
82+ if (mlink->wcid.link_id == msta->pri_link)
83+ msta->pri_link = msta->sec_link;
84+
85+ if (sta->valid_links & ~(BIT(msta->pri_link)))
86+ msta->sec_link = __ffs(sta->valid_links & ~(BIT(msta->pri_link)));
87+ else
88+ msta->sec_link = msta->pri_link;
89+ }
90+
91+ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
92+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, mlink->wcid.idx);
93+ mt76_wcid_mask_clear(dev->mt76.wcid_phy_mask, mlink->wcid.idx);
94+
95+ if (mlink != &msta->deflink)
96+ kfree(mlink);
97+}
98+
99+static int mt7996_add_link_sta(struct mt7996_dev *dev,
100+ struct ieee80211_bss_conf *conf,
101+ struct mt7996_bss_conf *mconf,
102+ struct ieee80211_link_sta *link_sta, bool assoc)
103+{
104+ struct ieee80211_sta *sta = link_sta->sta;
105+ struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv;
106+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
107+ u8 link_id = link_sta->link_id;
108+ struct mt7996_link_sta *mlink = NULL;
109+ int idx, ret;
110+
111+ if (!rcu_access_pointer(msta->link[link_id])) {
112+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
113+ if (idx < 0)
114+ return -ENOSPC;
115+
116+ if (sta->mlo) {
117+ mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
118+ if (!mlink)
119+ return -ENOMEM;
120+ } else {
121+ mlink = &msta->deflink;
122+ }
123+
124+ INIT_LIST_HEAD(&mlink->rc_list);
125+ INIT_LIST_HEAD(&mlink->wcid.poll_list);
126+ msta->vif = mvif;
127+ mlink->wcid.sta = 1;
128+ mlink->wcid.idx = idx;
129+ mlink->wcid.phy_idx = mconf->phy->mt76->band_idx;
130+ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
131+ mlink->wcid.def_wcid = &msta->deflink.wcid;
132+ mlink->sta = msta;
133+ if (sta->valid_links) {
134+ mlink->wcid.link_valid = true;
135+ mlink->wcid.link_id = link_id;
136+ if (sta->valid_links & ~(BIT(msta->pri_link)))
137+ msta->sec_link = __ffs(sta->valid_links &
138+ ~(BIT(msta->pri_link)));
139+ else
140+ msta->sec_link = msta->pri_link;
141+ }
142+
143+ rcu_assign_pointer(msta->link[link_id], mlink);
144+
145+ ewma_signal_init(&mlink->wcid.rssi);
146+ if (mconf->phy->mt76->band_idx == MT_BAND1)
147+ mt76_wcid_mask_set(dev->mt76.wcid_phy_mask, idx);
148+ rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid);
149+ mt76_wcid_init(&mlink->wcid);
150+ }
151+
152+ if (!assoc)
153+ return 0;
154+
155+ if (!mlink)
156+ mlink = mlink_dereference_protected(msta, link_id);
157+ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
158+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
159+
160+ ret = mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
161+ if (ret)
162+ goto error;
163+
164+ ret = mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
165+ if (ret)
166+ goto error;
167+
168+ ewma_avg_signal_init(&mlink->avg_ack_signal);
169+
170+ return 0;
171+error:
172+ mt7996_remove_link_sta(dev, conf, mconf, link_sta, mlink);
173+ return ret;
174+}
175+
176+static void
177+mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
178+ struct ieee80211_sta *sta, unsigned long rem)
179+{
180+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
181+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
182+ unsigned int link_id;
183+
184+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
185+ struct mt7996_bss_conf *mconf =
186+ mconf_dereference_protected(mvif, link_id);
187+ struct mt7996_link_sta *mlink =
188+ mlink_dereference_protected(msta, link_id);
189+ struct ieee80211_bss_conf *conf =
190+ link_conf_dereference_protected(vif, link_id);
191+ struct ieee80211_link_sta *link_sta =
192+ link_sta_dereference_protected(sta, link_id);
193+
194+ mt7996_remove_link_sta(dev, conf, mconf, link_sta, mlink);
195+ }
196+}
197+
198+static int
199+mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
200+ struct ieee80211_sta *sta, unsigned long add,
201+ bool assoc)
202+{
203+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
204+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
205+ struct mt7996_link_sta *mlink;
206+ unsigned int link_id;
207+ int i, ret;
208+
209+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
210+ struct mt7996_bss_conf *mconf =
211+ mconf_dereference_protected(mvif, link_id);
212+ struct ieee80211_bss_conf *conf =
213+ link_conf_dereference_protected(vif, link_id);
214+ struct ieee80211_link_sta *link_sta =
215+ link_sta_dereference_protected(sta, link_id);
216+
217+ ret = mt7996_add_link_sta(dev, conf, mconf, link_sta, assoc);
218+ if (ret)
219+ goto error;
220+ }
221+
222+ if (!assoc)
223+ return 0;
224+
225+ mlink = mlink_dereference_protected(msta, msta->pri_link);
226+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
227+ struct mt76_txq *mtxq;
228+
229+ if (!sta->txq[i])
230+ continue;
231+ mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
232+ mtxq->wcid = mlink->wcid.idx;
233+ }
234+
235+ ret = mt7996_mcu_add_mld_sta(dev, vif, sta, add);
236+ if (ret)
237+ goto error;
238+
239+ return 0;
240+error:
241+ mt7996_mac_sta_remove_links(dev, vif, sta, add);
242+ return ret;
243+}
244+
245 int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
246 struct ieee80211_sta *sta)
247 {
248 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
249- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
250 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
251- struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
252- struct mt7996_link_sta *mlink = &msta->deflink;
253- u8 band_idx = mconf->phy->mt76->band_idx;
254- int idx;
255+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
256+ struct mt7996_bss_conf *mconf;
257+ u8 link_id = sta->valid_links ? __ffs(sta->valid_links) : 0;
258+ unsigned long add = BIT(link_id);
259+ int ret;
260
261 #ifdef CONFIG_MTK_VENDOR
262 struct mt7996_phy *phy = &dev->phy;
263 #endif
264
265- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
266- if (idx < 0)
267- return -ENOSPC;
268-
269- INIT_LIST_HEAD(&mlink->rc_list);
270- INIT_LIST_HEAD(&mlink->wcid.poll_list);
271- msta->vif = mvif;
272- mlink->wcid.sta = 1;
273- mlink->wcid.idx = idx;
274- mlink->wcid.phy_idx = band_idx;
275- mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
276- mlink->sta = msta;
277-
278- rcu_assign_pointer(msta->link[0], mlink);
279+ msta->pri_link = link_id;
280+ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false);
281+ if (ret)
282+ return ret;
283
284 #ifdef CONFIG_MTK_VENDOR
285+ mconf = mconf_dereference_protected(mvif, link_id);
286 mt7996_vendor_amnt_sta_remove(mconf->phy, sta);
287 #endif
288
289 #ifdef CONFIG_MTK_VENDOR
290- switch (band_idx) {
291+ switch (mconf->phy->mt76->band_idx) {
292 case MT_BAND1:
293 phy = mt7996_phy2(dev);
294 break;
295@@ -986,28 +1178,11 @@ void mt7996_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
296 struct ieee80211_sta *sta)
297 {
298 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
299- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
300- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
301- struct mt7996_bss_conf *mconf;
302- struct mt7996_link_sta *mlink;
303- struct ieee80211_bss_conf *conf;
304- struct ieee80211_link_sta *link_sta;
305+ unsigned long add = sta->valid_links ?: BIT(0);
306
307 mutex_lock(&dev->mt76.mutex);
308
309- conf = link_conf_dereference_protected(vif, 0);
310- mconf = mconf_dereference_protected(mvif, 0);
311- link_sta = link_sta_dereference_protected(sta, 0);
312- mlink = mlink_dereference_protected(msta, 0);
313-
314- mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
315- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
316-
317- mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
318- mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
319- mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
320-
321- ewma_avg_signal_init(&mlink->avg_ack_signal);
322+ mt7996_mac_sta_add_links(dev, vif, sta, add, true);
323
324 mutex_unlock(&dev->mt76.mutex);
325 }
326@@ -1016,34 +1191,9 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
327 struct ieee80211_sta *sta)
328 {
329 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
330- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
331- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
332- struct mt7996_bss_conf *mconf;
333- struct mt7996_link_sta *mlink;
334- struct ieee80211_bss_conf *conf;
335- struct ieee80211_link_sta *link_sta;
336- int i;
337-
338- conf = link_conf_dereference_protected(vif, 0);
339- mconf = mconf_dereference_protected(mvif, 0);
340- link_sta = link_sta_dereference_protected(sta, 0);
341- mlink = mlink_dereference_protected(msta, 0);
342- mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
343-
344- mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
345- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
346-
347- for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
348- mt7996_mac_twt_teardown_flow(dev, mlink, i);
349+ unsigned long rem = sta->valid_links ?: BIT(0);
350
351- spin_lock_bh(&mdev->sta_poll_lock);
352- if (!list_empty(&mlink->wcid.poll_list))
353- list_del_init(&mlink->wcid.poll_list);
354- if (!list_empty(&mlink->rc_list))
355- list_del_init(&mlink->rc_list);
356- spin_unlock_bh(&mdev->sta_poll_lock);
357-
358- rcu_assign_pointer(msta->link[0], NULL);
359+ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
360 }
361
362 static void mt7996_tx(struct ieee80211_hw *hw,
363@@ -2161,6 +2311,32 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
364 return ret;
365 }
366
367+static int
368+mt7996_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
369+ struct ieee80211_sta *sta, u16 old_links, u16 new_links)
370+{
371+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
372+ unsigned long add = new_links & ~old_links;
373+ unsigned long rem = old_links & ~new_links;
374+ int ret = 0;
375+
376+ mutex_lock(&dev->mt76.mutex);
377+
378+ if (rem)
379+ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
380+
381+ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false);
382+ if (ret)
383+ goto remove;
384+
385+ goto out;
386+remove:
387+ mt7996_mac_sta_remove_links(dev, vif, sta, add);
388+out:
389+ mutex_unlock(&dev->mt76.mutex);
390+ return ret;
391+}
392+
393 const struct ieee80211_ops mt7996_ops = {
394 .tx = mt7996_tx,
395 .start = mt7996_start,
396@@ -2218,4 +2394,5 @@ const struct ieee80211_ops mt7996_ops = {
397 .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
398 .switch_vif_chanctx = mt7996_switch_vif_chanctx,
399 .change_vif_links = mt7996_change_vif_links,
400+ .change_sta_links = mt7996_change_sta_links,
401 };
402diff --git a/mt7996/mcu.c b/mt7996/mcu.c
403index 0eccc112d..ed854b473 100644
404--- a/mt7996/mcu.c
405+++ b/mt7996/mcu.c
406@@ -2425,6 +2425,123 @@ out:
407 MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
408 }
409
410+static void
411+mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
412+ struct ieee80211_sta *sta)
413+{
414+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
415+ struct sta_rec_mld_setup *mld_setup;
416+ struct mld_setup_link *mld_setup_link;
417+ struct mt7996_link_sta *mlink;
418+ struct mt7996_bss_conf *mconf;
419+ struct tlv *tlv;
420+ unsigned long valid_links = sta->valid_links;
421+ unsigned int link_id;
422+
423+ mlink = mlink_dereference_protected(msta, msta->pri_link);
424+ if (!mlink)
425+ return;
426+
427+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD,
428+ sizeof(*mld_setup) +
429+ sizeof(struct mld_setup_link) *
430+ hweight16(sta->valid_links));
431+
432+ mld_setup = (struct sta_rec_mld_setup *)tlv;
433+ memcpy(mld_setup->mld_addr, sta->addr, ETH_ALEN);
434+ mld_setup->setup_wcid = cpu_to_le16(mlink->wcid.idx);
435+ mld_setup->primary_id = cpu_to_le16(mlink->wcid.idx);
436+ if (msta->sec_link != msta->pri_link) {
437+ mlink = mlink_dereference_protected(msta, msta->sec_link);
438+ if (!mlink)
439+ return;
440+ }
441+ mld_setup->seconed_id = cpu_to_le16(mlink->wcid.idx);
442+ mld_setup->link_num = hweight16(sta->valid_links);
443+
444+ mld_setup_link = (struct mld_setup_link *)mld_setup->link_info;
445+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
446+ mlink = mlink_dereference_protected(msta, link_id);
447+ mconf = mconf_dereference_protected(msta->vif, link_id);
448+
449+ mld_setup_link->wcid = cpu_to_le16(mlink->wcid.idx);
450+ mld_setup_link->bss_idx = mconf->mt76.idx;
451+ mld_setup_link++;
452+ }
453+}
454+
455+static void
456+mt7996_mcu_sta_eht_mld_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
457+ struct ieee80211_sta *sta)
458+{
459+ struct sta_rec_eht_mld *eht_mld;
460+ struct tlv *tlv;
461+ int i;
462+
463+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld));
464+ eht_mld = (struct sta_rec_eht_mld *)tlv;
465+
466+ for (i = 0; i < ARRAY_SIZE(eht_mld->str_cap); i++)
467+ eht_mld->str_cap[i] = 0x7;
468+ /* TODO:
469+ eht_mld->nsep = ;
470+ eht_mld->eml_cap = cpu_to_le16()
471+ */
472+}
473+
474+int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
475+ struct ieee80211_sta *sta, unsigned long add)
476+{
477+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
478+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
479+ unsigned int link_id;
480+
481+ if (!sta->mlo)
482+ return 0;
483+
484+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
485+ struct mt7996_bss_conf *mconf =
486+ mconf_dereference_protected(mvif, link_id);
487+ struct mt7996_link_sta *mlink =
488+ mlink_dereference_protected(msta, link_id);
489+ struct sk_buff *skb;
490+ int ret;
491+
492+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
493+ &mlink->wcid,
494+ MT7996_STA_UPDATE_MAX_SIZE);
495+ if (IS_ERR(skb))
496+ return PTR_ERR(skb);
497+ /* starec mld setup */
498+ mt7996_mcu_sta_mld_setup_tlv(dev, skb, sta);
499+ /* starec eht mld */
500+ mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta);
501+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
502+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
503+ if (ret)
504+ return ret;
505+ }
506+ return 0;
507+}
508+int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
509+ struct mt7996_bss_conf *mconf,
510+ struct mt7996_link_sta *mlink)
511+{
512+ struct sk_buff *skb;
513+
514+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76,
515+ &mconf->mt76,
516+ &mlink->wcid,
517+ MT7996_STA_UPDATE_MAX_SIZE);
518+ if (IS_ERR(skb))
519+ return PTR_ERR(skb);
520+
521+ mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_TEARDOWN, sizeof(struct tlv));
522+
523+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
524+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
525+}
526+
527 static int
528 mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
529 struct sk_buff *skb,
530diff --git a/mt7996/mcu.h b/mt7996/mcu.h
531index 814072e3a..ee36cf5ed 100644
532--- a/mt7996/mcu.h
533+++ b/mt7996/mcu.h
534@@ -698,6 +698,35 @@ struct sta_rec_hdr_trans {
535 u8 mesh;
536 } __packed;
537
538+struct sta_rec_mld_setup {
539+ __le16 tag;
540+ __le16 len;
541+ u8 mld_addr[ETH_ALEN];
542+ __le16 primary_id;
543+ __le16 seconed_id;
544+ __le16 setup_wcid;
545+ u8 link_num;
546+ u8 info;
547+ u8 __rsv[2];
548+ u8 link_info[];
549+} __packed;
550+
551+struct mld_setup_link {
552+ __le16 wcid;
553+ u8 bss_idx;
554+ u8 __rsv[1];
555+} __packed;
556+
557+struct sta_rec_eht_mld {
558+ __le16 tag;
559+ __le16 len;
560+ u8 nsep;
561+ u8 __rsv1[2];
562+ u8 str_cap[__MT_MAX_BAND];
563+ __le16 eml_cap;
564+ u8 __rsv2[4];
565+} __packed;
566+
567 struct hdr_trans_en {
568 __le16 tag;
569 __le16 len;
570diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
571index ed8c82e8c..913aff173 100644
572--- a/mt7996/mt7996.h
573+++ b/mt7996/mt7996.h
574@@ -329,6 +329,8 @@ struct mt7996_sta {
575 struct mt7996_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
576
577 struct mt7996_vif *vif;
578+ u8 pri_link;
579+ u8 sec_link;
580 };
581
582 struct mt7996_bss_conf {
583@@ -856,6 +858,9 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
584 struct mt7996_bss_conf *mconf,
585 struct ieee80211_link_sta *link_sta,
586 struct mt7996_link_sta *mlink, bool enable, bool newly);
587+int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
588+ struct mt7996_bss_conf *mconf,
589+ struct mt7996_link_sta *mlink);
590 int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
591 struct ieee80211_ampdu_params *params,
592 bool add);
593@@ -879,6 +884,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
594 struct mt7996_bss_conf *mconf,
595 struct ieee80211_link_sta *link_sta,
596 struct mt7996_link_sta *mlink, bool changed);
597+int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
598+ struct ieee80211_sta *sta, unsigned long add);
599 int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
600 int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
601 int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf);
602--
6032.39.2
604