blob: 19b0be2765f494f030f7492cad7956712bf64618 [file] [log] [blame]
developerd0c89452024-10-11 16:53:27 +08001From 62e749b2b89a799e0d137983f4dabc1eeb3ebad8 Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: Shayne Chen <shayne.chen@mediatek.com>
3Date: Wed, 29 Nov 2023 10:12:39 +0800
developerd0c89452024-10-11 16:53:27 +08004Subject: [PATCH 083/223] mtk: mt76: mt7996: support multi-link sta links and
developer66e89bc2024-04-23 14:50:01 +08005 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---
developerd0c89452024-10-11 16:53:27 +080015 mt7996/main.c | 318 +++++++++++++++++++++++++++++++++++++-----------
developer05f3b2b2024-08-19 19:17:34 +080016 mt7996/mcu.c | 117 ++++++++++++++++++
17 mt7996/mcu.h | 29 +++++
18 mt7996/mt7996.h | 7 ++
developerd0c89452024-10-11 16:53:27 +080019 4 files changed, 400 insertions(+), 71 deletions(-)
developer66e89bc2024-04-23 14:50:01 +080020
developer66e89bc2024-04-23 14:50:01 +080021diff --git a/mt7996/main.c b/mt7996/main.c
developerd0c89452024-10-11 16:53:27 +080022index dc7ee54c..106e8534 100644
developer66e89bc2024-04-23 14:50:01 +080023--- a/mt7996/main.c
24+++ b/mt7996/main.c
developerd0c89452024-10-11 16:53:27 +080025@@ -926,42 +926,234 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
developer66e89bc2024-04-23 14:50:01 +080026 mutex_unlock(&dev->mt76.mutex);
27 }
28
29+static void mt7996_remove_link_sta(struct mt7996_dev *dev,
30+ struct ieee80211_bss_conf *conf,
31+ struct mt7996_bss_conf *mconf,
32+ struct ieee80211_link_sta *link_sta,
33+ struct mt7996_link_sta *mlink)
34+{
35+ struct ieee80211_sta *sta = link_sta->sta;
36+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
37+ int i;
38+
39+ if (!mlink)
40+ return;
41+
42+ for (i = 0; i < ARRAY_SIZE(mlink->wcid.aggr); i++)
43+ mt76_rx_aggr_stop(&dev->mt76, &mlink->wcid, i);
44+
45+ if (sta->mlo)
46+ mt7996_mcu_teardown_mld_sta(dev, mconf, mlink);
47+ else
48+ mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
49+
50+ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
51+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
52+
53+ for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
54+ mt7996_mac_twt_teardown_flow(dev, mlink, i);
55+
56+ rcu_assign_pointer(mlink->sta->link[mlink->wcid.link_id], NULL);
57+
58+ spin_lock_bh(&dev->mt76.sta_poll_lock);
59+ if (!list_empty(&mlink->wcid.poll_list))
60+ list_del_init(&mlink->wcid.poll_list);
61+ if (!list_empty(&mlink->rc_list))
62+ list_del_init(&mlink->rc_list);
63+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
64+
65+ /* TODO: update primary link */
66+ if (sta->valid_links) {
67+ if (mlink->wcid.link_id == msta->pri_link)
68+ msta->pri_link = msta->sec_link;
69+
70+ if (sta->valid_links & ~(BIT(msta->pri_link)))
71+ msta->sec_link = __ffs(sta->valid_links & ~(BIT(msta->pri_link)));
72+ else
73+ msta->sec_link = msta->pri_link;
74+ }
75+
76+ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
77+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, mlink->wcid.idx);
78+ mt76_wcid_mask_clear(dev->mt76.wcid_phy_mask, mlink->wcid.idx);
79+
80+ if (mlink != &msta->deflink)
81+ kfree(mlink);
82+}
83+
84+static int mt7996_add_link_sta(struct mt7996_dev *dev,
85+ struct ieee80211_bss_conf *conf,
86+ struct mt7996_bss_conf *mconf,
87+ struct ieee80211_link_sta *link_sta, bool assoc)
88+{
89+ struct ieee80211_sta *sta = link_sta->sta;
90+ struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv;
91+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
92+ u8 link_id = link_sta->link_id;
93+ struct mt7996_link_sta *mlink = NULL;
94+ int idx, ret;
95+
96+ if (!rcu_access_pointer(msta->link[link_id])) {
97+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
98+ if (idx < 0)
99+ return -ENOSPC;
100+
101+ if (sta->mlo) {
102+ mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
103+ if (!mlink)
104+ return -ENOMEM;
105+ } else {
106+ mlink = &msta->deflink;
107+ }
108+
109+ INIT_LIST_HEAD(&mlink->rc_list);
110+ INIT_LIST_HEAD(&mlink->wcid.poll_list);
111+ msta->vif = mvif;
112+ mlink->wcid.sta = 1;
113+ mlink->wcid.idx = idx;
114+ mlink->wcid.phy_idx = mconf->phy->mt76->band_idx;
115+ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
116+ mlink->wcid.def_wcid = &msta->deflink.wcid;
117+ mlink->sta = msta;
118+ if (sta->valid_links) {
119+ mlink->wcid.link_valid = true;
120+ mlink->wcid.link_id = link_id;
121+ if (sta->valid_links & ~(BIT(msta->pri_link)))
122+ msta->sec_link = __ffs(sta->valid_links &
123+ ~(BIT(msta->pri_link)));
124+ else
125+ msta->sec_link = msta->pri_link;
126+ }
127+
128+ rcu_assign_pointer(msta->link[link_id], mlink);
129+
130+ ewma_signal_init(&mlink->wcid.rssi);
131+ if (mconf->phy->mt76->band_idx == MT_BAND1)
132+ mt76_wcid_mask_set(dev->mt76.wcid_phy_mask, idx);
133+ rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid);
134+ mt76_wcid_init(&mlink->wcid);
135+ }
136+
137+ if (!assoc)
138+ return 0;
139+
140+ if (!mlink)
141+ mlink = mlink_dereference_protected(msta, link_id);
142+ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
143+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
144+
145+ ret = mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
146+ if (ret)
147+ goto error;
148+
149+ ret = mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
150+ if (ret)
151+ goto error;
152+
153+ ewma_avg_signal_init(&mlink->avg_ack_signal);
154+
155+ return 0;
156+error:
157+ mt7996_remove_link_sta(dev, conf, mconf, link_sta, mlink);
158+ return ret;
159+}
160+
161+static void
162+mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
163+ struct ieee80211_sta *sta, unsigned long rem)
164+{
165+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
166+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
167+ unsigned int link_id;
168+
169+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
170+ struct mt7996_bss_conf *mconf =
171+ mconf_dereference_protected(mvif, link_id);
172+ struct mt7996_link_sta *mlink =
173+ mlink_dereference_protected(msta, link_id);
174+ struct ieee80211_bss_conf *conf =
175+ link_conf_dereference_protected(vif, link_id);
176+ struct ieee80211_link_sta *link_sta =
177+ link_sta_dereference_protected(sta, link_id);
178+
179+ mt7996_remove_link_sta(dev, conf, mconf, link_sta, mlink);
180+ }
181+}
182+
183+static int
184+mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
185+ struct ieee80211_sta *sta, unsigned long add,
186+ bool assoc)
187+{
188+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
189+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
190+ struct mt7996_link_sta *mlink;
191+ unsigned int link_id;
192+ int i, ret;
193+
194+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
195+ struct mt7996_bss_conf *mconf =
196+ mconf_dereference_protected(mvif, link_id);
197+ struct ieee80211_bss_conf *conf =
198+ link_conf_dereference_protected(vif, link_id);
199+ struct ieee80211_link_sta *link_sta =
200+ link_sta_dereference_protected(sta, link_id);
201+
202+ ret = mt7996_add_link_sta(dev, conf, mconf, link_sta, assoc);
203+ if (ret)
204+ goto error;
205+ }
206+
207+ if (!assoc)
208+ return 0;
209+
210+ mlink = mlink_dereference_protected(msta, msta->pri_link);
211+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
212+ struct mt76_txq *mtxq;
213+
214+ if (!sta->txq[i])
215+ continue;
216+ mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
217+ mtxq->wcid = mlink->wcid.idx;
218+ }
219+
220+ ret = mt7996_mcu_add_mld_sta(dev, vif, sta, add);
221+ if (ret)
222+ goto error;
223+
224+ return 0;
225+error:
226+ mt7996_mac_sta_remove_links(dev, vif, sta, add);
227+ return ret;
228+}
229+
230 int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
231 struct ieee80211_sta *sta)
232 {
233 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
234- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
235 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
236- struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
237- struct mt7996_link_sta *mlink = &msta->deflink;
238- u8 band_idx = mconf->phy->mt76->band_idx;
239- int idx;
240+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
241+ struct mt7996_bss_conf *mconf;
242+ u8 link_id = sta->valid_links ? __ffs(sta->valid_links) : 0;
243+ unsigned long add = BIT(link_id);
244+ int ret;
245
246 #ifdef CONFIG_MTK_VENDOR
247 struct mt7996_phy *phy = &dev->phy;
248 #endif
249
250- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
251- if (idx < 0)
252- return -ENOSPC;
253-
254- INIT_LIST_HEAD(&mlink->rc_list);
255- INIT_LIST_HEAD(&mlink->wcid.poll_list);
256- msta->vif = mvif;
257- mlink->wcid.sta = 1;
258- mlink->wcid.idx = idx;
259- mlink->wcid.phy_idx = band_idx;
260- mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
261- mlink->sta = msta;
262-
263- rcu_assign_pointer(msta->link[0], mlink);
264+ msta->pri_link = link_id;
265+ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false);
266+ if (ret)
267+ return ret;
268
269 #ifdef CONFIG_MTK_VENDOR
270+ mconf = mconf_dereference_protected(mvif, link_id);
271 mt7996_vendor_amnt_sta_remove(mconf->phy, sta);
272 #endif
273
274 #ifdef CONFIG_MTK_VENDOR
275- switch (band_idx) {
276+ switch (mconf->phy->mt76->band_idx) {
277 case MT_BAND1:
278 phy = mt7996_phy2(dev);
279 break;
developerd0c89452024-10-11 16:53:27 +0800280@@ -984,69 +1176,26 @@ int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
281 struct ieee80211_sta *sta, enum mt76_sta_event ev)
developer66e89bc2024-04-23 14:50:01 +0800282 {
283 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
284- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
285- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
286- struct mt7996_bss_conf *mconf;
287- struct mt7996_link_sta *mlink;
288- struct ieee80211_bss_conf *conf;
289- struct ieee80211_link_sta *link_sta;
290+ unsigned long add = sta->valid_links ?: BIT(0);
developerd0c89452024-10-11 16:53:27 +0800291+ int ret = 0;
developer66e89bc2024-04-23 14:50:01 +0800292
293 mutex_lock(&dev->mt76.mutex);
294
developerd0c89452024-10-11 16:53:27 +0800295- if (ev == MT76_STA_EVENT_ASSOC) {
296- mt7996_mac_wtbl_update(dev, msta->wcid.idx,
297- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
developer66e89bc2024-04-23 14:50:01 +0800298-
developerd0c89452024-10-11 16:53:27 +0800299- conf = link_conf_dereference_protected(vif, 0);
300- mconf = mconf_dereference_protected(mvif, 0);
301- link_sta = link_sta_dereference_protected(sta, 0);
302- mlink = mlink_dereference_protected(msta, 0);
developer66e89bc2024-04-23 14:50:01 +0800303-
developerd0c89452024-10-11 16:53:27 +0800304- mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
305- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
306-
307- mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
308- mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
309- mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
developer66e89bc2024-04-23 14:50:01 +0800310-
developerd0c89452024-10-11 16:53:27 +0800311- ewma_avg_signal_init(&mlink->avg_ack_signal);
312- }
313+ if (ev == MT76_STA_EVENT_ASSOC)
314+ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, true);
developer66e89bc2024-04-23 14:50:01 +0800315
316 mutex_unlock(&dev->mt76.mutex);
developerd0c89452024-10-11 16:53:27 +0800317+
318+ return ret;
developer66e89bc2024-04-23 14:50:01 +0800319 }
developerd0c89452024-10-11 16:53:27 +0800320
321 void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
developer66e89bc2024-04-23 14:50:01 +0800322 struct ieee80211_sta *sta)
323 {
324 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
325- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
326- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
327- struct mt7996_bss_conf *mconf;
328- struct mt7996_link_sta *mlink;
329- struct ieee80211_bss_conf *conf;
330- struct ieee80211_link_sta *link_sta;
331- int i;
332-
333- conf = link_conf_dereference_protected(vif, 0);
334- mconf = mconf_dereference_protected(mvif, 0);
335- link_sta = link_sta_dereference_protected(sta, 0);
336- mlink = mlink_dereference_protected(msta, 0);
337- mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
338-
339- mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
340- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
341-
342- for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
343- mt7996_mac_twt_teardown_flow(dev, mlink, i);
344+ unsigned long rem = sta->valid_links ?: BIT(0);
345
346- spin_lock_bh(&mdev->sta_poll_lock);
347- if (!list_empty(&mlink->wcid.poll_list))
348- list_del_init(&mlink->wcid.poll_list);
349- if (!list_empty(&mlink->rc_list))
350- list_del_init(&mlink->rc_list);
351- spin_unlock_bh(&mdev->sta_poll_lock);
352-
353- rcu_assign_pointer(msta->link[0], NULL);
354+ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
355 }
356
357 static void mt7996_tx(struct ieee80211_hw *hw,
developerd0c89452024-10-11 16:53:27 +0800358@@ -2161,6 +2310,32 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developer66e89bc2024-04-23 14:50:01 +0800359 return ret;
360 }
361
362+static int
363+mt7996_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
364+ struct ieee80211_sta *sta, u16 old_links, u16 new_links)
365+{
366+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
367+ unsigned long add = new_links & ~old_links;
368+ unsigned long rem = old_links & ~new_links;
369+ int ret = 0;
370+
371+ mutex_lock(&dev->mt76.mutex);
372+
373+ if (rem)
374+ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
375+
376+ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false);
377+ if (ret)
378+ goto remove;
379+
380+ goto out;
381+remove:
382+ mt7996_mac_sta_remove_links(dev, vif, sta, add);
383+out:
384+ mutex_unlock(&dev->mt76.mutex);
385+ return ret;
386+}
387+
388 const struct ieee80211_ops mt7996_ops = {
developer05f3b2b2024-08-19 19:17:34 +0800389 .add_chanctx = ieee80211_emulate_add_chanctx,
390 .remove_chanctx = ieee80211_emulate_remove_chanctx,
developerd0c89452024-10-11 16:53:27 +0800391@@ -2222,4 +2397,5 @@ const struct ieee80211_ops mt7996_ops = {
developer66e89bc2024-04-23 14:50:01 +0800392 .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
393 .switch_vif_chanctx = mt7996_switch_vif_chanctx,
394 .change_vif_links = mt7996_change_vif_links,
395+ .change_sta_links = mt7996_change_sta_links,
396 };
397diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800398index 081e9ca9..96d4d5b0 100644
developer66e89bc2024-04-23 14:50:01 +0800399--- a/mt7996/mcu.c
400+++ b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800401@@ -2433,6 +2433,123 @@ out:
developer66e89bc2024-04-23 14:50:01 +0800402 MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
403 }
404
405+static void
406+mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
407+ struct ieee80211_sta *sta)
408+{
409+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
410+ struct sta_rec_mld_setup *mld_setup;
411+ struct mld_setup_link *mld_setup_link;
412+ struct mt7996_link_sta *mlink;
413+ struct mt7996_bss_conf *mconf;
414+ struct tlv *tlv;
415+ unsigned long valid_links = sta->valid_links;
416+ unsigned int link_id;
417+
418+ mlink = mlink_dereference_protected(msta, msta->pri_link);
419+ if (!mlink)
420+ return;
421+
422+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD,
423+ sizeof(*mld_setup) +
424+ sizeof(struct mld_setup_link) *
425+ hweight16(sta->valid_links));
426+
427+ mld_setup = (struct sta_rec_mld_setup *)tlv;
428+ memcpy(mld_setup->mld_addr, sta->addr, ETH_ALEN);
429+ mld_setup->setup_wcid = cpu_to_le16(mlink->wcid.idx);
430+ mld_setup->primary_id = cpu_to_le16(mlink->wcid.idx);
431+ if (msta->sec_link != msta->pri_link) {
432+ mlink = mlink_dereference_protected(msta, msta->sec_link);
433+ if (!mlink)
434+ return;
435+ }
436+ mld_setup->seconed_id = cpu_to_le16(mlink->wcid.idx);
437+ mld_setup->link_num = hweight16(sta->valid_links);
438+
439+ mld_setup_link = (struct mld_setup_link *)mld_setup->link_info;
440+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
441+ mlink = mlink_dereference_protected(msta, link_id);
442+ mconf = mconf_dereference_protected(msta->vif, link_id);
443+
444+ mld_setup_link->wcid = cpu_to_le16(mlink->wcid.idx);
445+ mld_setup_link->bss_idx = mconf->mt76.idx;
446+ mld_setup_link++;
447+ }
448+}
449+
450+static void
451+mt7996_mcu_sta_eht_mld_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
452+ struct ieee80211_sta *sta)
453+{
454+ struct sta_rec_eht_mld *eht_mld;
455+ struct tlv *tlv;
456+ int i;
457+
458+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld));
459+ eht_mld = (struct sta_rec_eht_mld *)tlv;
460+
461+ for (i = 0; i < ARRAY_SIZE(eht_mld->str_cap); i++)
462+ eht_mld->str_cap[i] = 0x7;
463+ /* TODO:
464+ eht_mld->nsep = ;
465+ eht_mld->eml_cap = cpu_to_le16()
466+ */
467+}
468+
469+int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
470+ struct ieee80211_sta *sta, unsigned long add)
471+{
472+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
473+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
474+ unsigned int link_id;
475+
476+ if (!sta->mlo)
477+ return 0;
478+
479+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
480+ struct mt7996_bss_conf *mconf =
481+ mconf_dereference_protected(mvif, link_id);
482+ struct mt7996_link_sta *mlink =
483+ mlink_dereference_protected(msta, link_id);
484+ struct sk_buff *skb;
485+ int ret;
486+
487+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
488+ &mlink->wcid,
489+ MT7996_STA_UPDATE_MAX_SIZE);
490+ if (IS_ERR(skb))
491+ return PTR_ERR(skb);
492+ /* starec mld setup */
493+ mt7996_mcu_sta_mld_setup_tlv(dev, skb, sta);
494+ /* starec eht mld */
495+ mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta);
496+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
497+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
498+ if (ret)
499+ return ret;
500+ }
501+ return 0;
502+}
503+int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
504+ struct mt7996_bss_conf *mconf,
505+ struct mt7996_link_sta *mlink)
506+{
507+ struct sk_buff *skb;
508+
509+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76,
510+ &mconf->mt76,
511+ &mlink->wcid,
512+ MT7996_STA_UPDATE_MAX_SIZE);
513+ if (IS_ERR(skb))
514+ return PTR_ERR(skb);
515+
developer05f3b2b2024-08-19 19:17:34 +0800516+ mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, sizeof(struct tlv));
developer66e89bc2024-04-23 14:50:01 +0800517+
518+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
519+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
520+}
521+
522 static int
523 mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
524 struct sk_buff *skb,
525diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developer05f3b2b2024-08-19 19:17:34 +0800526index b15796dc..23d44cd3 100644
developer66e89bc2024-04-23 14:50:01 +0800527--- a/mt7996/mcu.h
528+++ b/mt7996/mcu.h
developer05f3b2b2024-08-19 19:17:34 +0800529@@ -692,6 +692,35 @@ struct sta_rec_hdr_trans {
developer66e89bc2024-04-23 14:50:01 +0800530 u8 mesh;
531 } __packed;
532
533+struct sta_rec_mld_setup {
534+ __le16 tag;
535+ __le16 len;
536+ u8 mld_addr[ETH_ALEN];
537+ __le16 primary_id;
538+ __le16 seconed_id;
539+ __le16 setup_wcid;
540+ u8 link_num;
541+ u8 info;
542+ u8 __rsv[2];
543+ u8 link_info[];
544+} __packed;
545+
546+struct mld_setup_link {
547+ __le16 wcid;
548+ u8 bss_idx;
549+ u8 __rsv[1];
550+} __packed;
551+
552+struct sta_rec_eht_mld {
553+ __le16 tag;
554+ __le16 len;
555+ u8 nsep;
556+ u8 __rsv1[2];
557+ u8 str_cap[__MT_MAX_BAND];
558+ __le16 eml_cap;
559+ u8 __rsv2[4];
560+} __packed;
561+
562 struct hdr_trans_en {
563 __le16 tag;
564 __le16 len;
565diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800566index 9b9b1f8f..f6933418 100644
developer66e89bc2024-04-23 14:50:01 +0800567--- a/mt7996/mt7996.h
568+++ b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800569@@ -331,6 +331,8 @@ struct mt7996_sta {
developer66e89bc2024-04-23 14:50:01 +0800570 struct mt7996_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
571
572 struct mt7996_vif *vif;
573+ u8 pri_link;
574+ u8 sec_link;
575 };
576
577 struct mt7996_bss_conf {
developerd0c89452024-10-11 16:53:27 +0800578@@ -861,6 +863,9 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
developer66e89bc2024-04-23 14:50:01 +0800579 struct mt7996_bss_conf *mconf,
580 struct ieee80211_link_sta *link_sta,
581 struct mt7996_link_sta *mlink, bool enable, bool newly);
582+int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
583+ struct mt7996_bss_conf *mconf,
584+ struct mt7996_link_sta *mlink);
585 int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
586 struct ieee80211_ampdu_params *params,
587 bool add);
developerd0c89452024-10-11 16:53:27 +0800588@@ -884,6 +889,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
developer66e89bc2024-04-23 14:50:01 +0800589 struct mt7996_bss_conf *mconf,
590 struct ieee80211_link_sta *link_sta,
591 struct mt7996_link_sta *mlink, bool changed);
592+int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
593+ struct ieee80211_sta *sta, unsigned long add);
594 int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
595 int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
596 int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf);
597--
developerd0c89452024-10-11 16:53:27 +08005982.45.2
developer66e89bc2024-04-23 14:50:01 +0800599