blob: 397fde19c976f9991d35344b77487125c18db708 [file] [log] [blame]
developerd0c89452024-10-11 16:53:27 +08001From d4e9a9535f8f51d6a4adabee9efc1a61b0798490 Mon Sep 17 00:00:00 2001
developer05f3b2b2024-08-19 19:17:34 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Tue, 23 Apr 2024 15:22:24 +0800
developerd0c89452024-10-11 16:53:27 +08004Subject: [PATCH 115/223] mtk: mt76: mt7996: add critical update support
developer05f3b2b2024-08-19 19:17:34 +08005
6Add critical update support
7modification: wmm configuration
8inclusion: channel switch
9(affiliated link's per-STA profile CSA/eCSA countdown is included)
10
11Fix the CU flag countdown issue of the non-CU link as reported from cert.
121. Avoid setting the CSA beacon twice during channel switch.
132. Raise the bypass_seq_bitmap up for the non-CU link.
14
15Reset the beacon when switching channels during CAC
16Otherwise, the FW will not be able to perform the CSA countdown.
17Also, modify the bpcc check since channel switch will add the bpcc twice
18(before CSA and after CSA).
19
developerd0c89452024-10-11 16:53:27 +080020Change-Id: Ibf92803d444ad672dd235f3584eec25a385082f4
21Change-Id: Id6ecd3de03bee0c2f412dd4dd1a57783c5d65fcf
developer05f3b2b2024-08-19 19:17:34 +080022Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
23Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
24---
25 mt76_connac_mcu.h | 2 +
26 mt7996/main.c | 107 +++++++++++++++++++++++++++++++++-------------
27 mt7996/mcu.c | 99 ++++++++++++++++++++++++++++++++++++++++++
28 mt7996/mcu.h | 26 ++++++++++-
29 mt7996/mt7996.h | 4 ++
30 5 files changed, 208 insertions(+), 30 deletions(-)
31
32diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developerd0c89452024-10-11 16:53:27 +080033index 86a2fdf8..0a4bf9b7 100644
developer05f3b2b2024-08-19 19:17:34 +080034--- a/mt76_connac_mcu.h
35+++ b/mt76_connac_mcu.h
developerd0c89452024-10-11 16:53:27 +080036@@ -1385,6 +1385,8 @@ enum {
developer05f3b2b2024-08-19 19:17:34 +080037 UNI_BSS_INFO_OFFLOAD = 25,
38 UNI_BSS_INFO_MLD = 26,
39 UNI_BSS_INFO_PM_DISABLE = 27,
40+ UNI_BSS_INFO_BCN_CRIT_UPDATE = 32,
41+ UNI_BSS_INFO_BCN_STA_PROF_CSA = 37,
42 };
43
44 enum {
45diff --git a/mt7996/main.c b/mt7996/main.c
developerd0c89452024-10-11 16:53:27 +080046index 0b62858b..9a265710 100644
developer05f3b2b2024-08-19 19:17:34 +080047--- a/mt7996/main.c
48+++ b/mt7996/main.c
49@@ -370,6 +370,7 @@ static int mt7996_add_bss_conf(struct mt7996_phy *phy,
50 mconf->mt76.band_idx = band_idx;
51 mconf->mt76.wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3;
52 mconf->link_id = link_id;
53+ mconf->bpcc = 0;
54
55 ret = mt7996_mcu_add_dev_info(phy, conf, mconf, true);
56 if (ret)
57@@ -979,7 +980,9 @@ static void mt7996_link_info_changed(struct ieee80211_hw *hw,
58 mconf->mt76.beacon_rates_idx =
59 mt7996_get_rates_table(hw, info, mconf, true, false);
60
61- mt7996_mcu_add_beacon(hw, info, mconf, info->enable_beacon);
62+ /* The CSA beacon will be set in channel_switch_beacon */
63+ if (!info->csa_active)
64+ mt7996_mcu_add_beacon(hw, info, mconf, info->enable_beacon);
65 }
66
67 if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
68@@ -1030,21 +1033,45 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
69 struct mt7996_dev *dev = mt7996_hw_dev(hw);
70 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
71 struct mt7996_phy *phy = mt7996_band_phy(hw, chandef->chan->band);
72- unsigned long valid_links = vif->valid_links ?: BIT(0);
73+ struct ieee80211_bss_conf *conf;
74+ struct mt7996_bss_conf *mconf;
75+ u16 valid_links = vif->valid_links ?: BIT(0);
76 unsigned int link_id;
77
78 mutex_lock(&dev->mt76.mutex);
79- for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
80- struct mt7996_bss_conf *mconf =
81- mconf_dereference_protected(mvif, link_id);
82- struct ieee80211_bss_conf *conf =
83- link_conf_dereference_protected(vif, link_id);
84+ link_id = mvif->band_to_link[phy->mt76->band_idx];
85
86- if (!mconf || phy != mconf->phy)
87- continue;
88+ if (!mvif->cs_ready_links)
89+ mvif->cs_link_id = link_id;
90+
91+ mvif->cs_ready_links |= BIT(link_id);
92+ if (mvif->cs_ready_links != valid_links)
93+ goto out;
94+
95+ link_id = mvif->cs_link_id;
96+ do {
97+ valid_links &= ~BIT(link_id);
98+ mconf = mconf_dereference_protected(mvif, link_id);
99+ conf = link_conf_dereference_protected(vif, link_id);
100+ if (!conf || !mconf)
101+ goto fail;
102+
103+ /* Reset the beacon when switching channels during CAC */
104+ if (link_id == mvif->cs_link_id &&
105+ !cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef, vif->type))
106+ mt7996_mcu_add_beacon(hw, conf, mconf, false);
107
108 mt7996_mcu_add_beacon(hw, conf, mconf, true);
109- }
110+ link_id = ffs(valid_links) - 1;
111+ } while (valid_links);
112+
113+out:
114+ mutex_unlock(&dev->mt76.mutex);
115+ return;
116+fail:
117+ mvif->cs_ready_links = 0;
118+ mvif->cs_link_id = IEEE80211_LINK_UNSPECIFIED;
119+ dev_err(dev->mt76.dev, "link %d: failed to switch beacon\n", link_id);
120 mutex_unlock(&dev->mt76.mutex);
121 }
122
developerd0c89452024-10-11 16:53:27 +0800123@@ -2538,32 +2565,54 @@ mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
developer05f3b2b2024-08-19 19:17:34 +0800124 int n_vifs,
125 enum ieee80211_chanctx_switch_mode mode)
126 {
127- struct mt7996_chanctx *old_ctx = mt7996_chanctx_get(vifs->old_ctx);
128- struct mt7996_chanctx *new_ctx = mt7996_chanctx_get(vifs->new_ctx);
129- struct mt7996_phy *phy = old_ctx->phy;
130+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
131+ struct mt7996_chanctx *old_ctx;
132+ struct mt7996_chanctx *new_ctx;
133+ struct mt7996_phy *phy;
134+ int i, ret = 0;
135
136- wiphy_info(hw->wiphy, "%s: old=%d, new=%d\n", __func__, vifs->old_ctx->def.chan->hw_value, vifs->new_ctx->def.chan->hw_value);
137+ for (i = 0; i < n_vifs; i++) {
138+ if (vifs[i].old_ctx == vifs[i].new_ctx)
139+ continue;
140
141- if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
142- new_ctx->nbss_assigned += n_vifs;
143- return 0;
144- }
145+ wiphy_info(hw->wiphy, "%s: old=%d, new=%d\n",
146+ __func__, vifs[i].old_ctx->def.chan->hw_value,
147+ vifs[i].new_ctx->def.chan->hw_value);
148
149- if (WARN_ON(old_ctx != phy->chanctx))
150- return -EINVAL;
151+ mutex_lock(&dev->mt76.mutex);
152
153- mutex_lock(&phy->dev->mt76.mutex);
154+ old_ctx = mt7996_chanctx_get(vifs[i].old_ctx);
155+ new_ctx = mt7996_chanctx_get(vifs[i].new_ctx);
156+ phy = old_ctx->phy;
157
158- phy->chanctx = new_ctx;
159- phy->mt76->radar_enabled = vifs->new_ctx->radar_enabled;
160- new_ctx->assigned = true;
161- new_ctx->chandef = vifs->new_ctx->def;
162- new_ctx->phy = phy;
163- new_ctx->nbss_assigned += n_vifs;
164+ if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
165+ new_ctx->nbss_assigned++;
166+ mutex_unlock(&dev->mt76.mutex);
167+ continue;
168+ }
169
170- mutex_unlock(&phy->dev->mt76.mutex);
171+ if (WARN_ON(old_ctx != phy->chanctx)) {
172+ ret = -EINVAL;
173+ mutex_unlock(&dev->mt76.mutex);
174+ goto out;
175+ }
176+
177+ phy->chanctx = new_ctx;
178+ phy->mt76->radar_enabled = vifs[i].new_ctx->radar_enabled;
179+ new_ctx->assigned = true;
180+ new_ctx->chandef = vifs[i].new_ctx->def;
181+ new_ctx->phy = phy;
182+ new_ctx->nbss_assigned++;
183+
184+ mutex_unlock(&dev->mt76.mutex);
185+
186+ ret = mt7996_set_channel(phy, &new_ctx->chandef);
187+ if (ret)
188+ goto out;
189+ }
190
191- return mt7996_set_channel(phy, &new_ctx->chandef);
192+out:
193+ return ret;
194 }
195
196 static int
197diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800198index f9ed473a..ea399a0b 100644
developer05f3b2b2024-08-19 19:17:34 +0800199--- a/mt7996/mcu.c
200+++ b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800201@@ -375,6 +375,7 @@ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
developer05f3b2b2024-08-19 19:17:34 +0800202 struct mt76_phy *mphy = (struct mt76_phy *)priv;
203 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
204 struct ieee80211_bss_conf *link_conf;
205+ unsigned long valid_links = vif->valid_links ?: BIT(0);
206 int link_id, band_idx = mphy->band_idx;
207
208 link_id = mvif->band_to_link[band_idx];
developerd0c89452024-10-11 16:53:27 +0800209@@ -383,7 +384,16 @@ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
developer05f3b2b2024-08-19 19:17:34 +0800210 if (!link_conf || !link_conf->csa_active || vif->type == NL80211_IFTYPE_STATION)
211 return;
212
213+ pr_info("%s: link_id=%d\n", __func__, link_id);
214+ mvif->cs_ready_links = 0;
215+ mvif->cs_link_id = IEEE80211_LINK_UNSPECIFIED;
216 ieee80211_csa_finish(vif, link_id);
217+ /* remove CSA for affiliated links */
218+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
219+ if (link_id == link_conf->link_id)
220+ continue;
221+ ieee80211_csa_finish(vif, link_id);
222+ }
223 }
224
225 static void
developerd0c89452024-10-11 16:53:27 +0800226@@ -3242,6 +3252,93 @@ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
developer05f3b2b2024-08-19 19:17:34 +0800227 }
228 }
229
230+static bool
231+mt7996_mcu_beacon_is_cu_link(struct sk_buff *skb, struct mt7996_bss_conf *mconf,
232+ u16 tail_offset)
233+{
234+ const struct element *elem;
235+ u8 *beacon_tail = skb->data + tail_offset;
236+ bool has_ml_ie = false;
237+ int bpcc;
238+
239+ for_each_element_extid(elem, WLAN_EID_EXT_EHT_MULTI_LINK,
240+ beacon_tail, skb->len - tail_offset)
241+ if (ieee80211_mle_type_ok(elem->data + 1,
242+ IEEE80211_ML_CONTROL_TYPE_BASIC,
243+ elem->datalen - 1)) {
244+ has_ml_ie = true;
245+ break;
246+ }
247+
248+ if (!has_ml_ie)
249+ return false;
250+
251+ bpcc = ieee80211_mle_get_bss_param_ch_cnt(elem->data + 1);
252+ if (bpcc < 0 || bpcc == mconf->bpcc)
253+ return false;
254+
255+ mconf->bpcc = bpcc;
256+
257+ return true;
258+}
259+
260+static void
261+mt7996_mcu_beacon_crit_update(struct sk_buff *rskb, struct sk_buff *skb,
262+ struct ieee80211_bss_conf *conf,
263+ struct mt7996_bss_conf *mconf,
264+ struct ieee80211_mutable_offsets *offs)
265+{
266+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
267+ struct bss_bcn_crit_update_tlv *crit;
268+ struct tlv *tlv;
269+
270+ if (!ieee80211_vif_is_mld(conf->vif) ||
271+ !(mgmt->u.beacon.capab_info & WLAN_CAPABILITY_PBCC))
272+ return;
273+
274+ tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CRIT_UPDATE, sizeof(*crit));
275+
276+ /* TODO: Support 11vMBSS */
277+ crit = (struct bss_bcn_crit_update_tlv *)tlv;
278+ crit->bss_bitmap = cpu_to_le32(BIT(0));
279+ /* The beacon of the CU link should be set in sequence
280+ * to ensure it appears in the air before the beacon of
281+ * the non-CU link.
282+ */
283+ if (!mt7996_mcu_beacon_is_cu_link(skb, mconf, offs->tim_offset))
284+ crit->bypass_seq_bitmap = cpu_to_le32(BIT(0));
285+ else
286+ crit->bypass_seq_bitmap = cpu_to_le32(0);
287+ crit->tim_ie_pos[0] = cpu_to_le16(offs->tim_offset);
288+ crit->cap_info_ie_pos[0] = cpu_to_le16(offsetof(struct ieee80211_mgmt,
289+ u.beacon.capab_info));
290+}
291+
292+static void
293+mt7996_mcu_beacon_sta_prof_csa(struct sk_buff *rskb,
294+ struct ieee80211_bss_conf *conf,
295+ struct ieee80211_mutable_offsets *offs)
296+{
297+ struct ieee80211_vif *vif = conf->vif;
298+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
299+ struct mt7996_bss_conf *cs_mconf;
300+ struct bss_bcn_sta_prof_cntdwn_tlv *sta_prof;
301+ struct tlv *tlv;
302+
303+ if (!ieee80211_vif_is_mld(vif) || !offs->sta_prof_cntdwn_offs[0])
304+ return;
305+
306+ cs_mconf = mconf_dereference_protected(mvif, mvif->cs_link_id);
307+ if (!cs_mconf)
308+ return;
309+
310+ tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_STA_PROF_CSA, sizeof(*sta_prof));
311+
312+ sta_prof = (struct bss_bcn_sta_prof_cntdwn_tlv *)tlv;
313+ sta_prof->sta_prof_csa_offs = cpu_to_le16(offs->sta_prof_cntdwn_offs[0] - 4);
314+ sta_prof->cs_bss_idx = cs_mconf->mt76.idx;
315+}
316+
317 static void
318 mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
319 struct sk_buff *rskb, struct sk_buff *skb,
developerd0c89452024-10-11 16:53:27 +0800320@@ -3322,6 +3419,8 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
developer05f3b2b2024-08-19 19:17:34 +0800321 mt7996_mcu_beacon_cont(dev, conf, rskb, skb, bcn, &offs);
322 mt7996_mcu_beacon_mbss(rskb, skb, conf, bcn, &offs);
323 mt7996_mcu_beacon_cntdwn(conf, rskb, skb, &offs);
324+ mt7996_mcu_beacon_sta_prof_csa(rskb, conf, &offs);
325+ mt7996_mcu_beacon_crit_update(rskb, skb, conf, mconf, &offs);
326 out:
327 dev_kfree_skb(skb);
328 return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
329diff --git a/mt7996/mcu.h b/mt7996/mcu.h
330index 5e217719..c39dcc3c 100644
331--- a/mt7996/mcu.h
332+++ b/mt7996/mcu.h
333@@ -503,6 +503,27 @@ struct bss_bcn_mbss_tlv {
334 __le16 offset[MAX_BEACON_NUM];
335 } __packed __aligned(4);
336
337+struct bss_bcn_crit_update_tlv {
338+ __le16 tag;
339+ __le16 len;
340+ __le32 bss_bitmap;
341+ /* Bypass the beacon sequence handling in firmware for the
342+ * BSSes in the bitmap. If the flag is set for a BSS, then the
343+ * firmware will not set the beacon of the BSS in sequence.
344+ */
345+ __le32 bypass_seq_bitmap;
346+ __le16 tim_ie_pos[32];
347+ __le16 cap_info_ie_pos[32];
348+} __packed;
349+
350+struct bss_bcn_sta_prof_cntdwn_tlv {
351+ __le16 tag;
352+ __le16 len;
353+ __le16 sta_prof_csa_offs;
354+ u8 cs_bss_idx;
355+ u8 pkt_content[9];
356+} __packed;
357+
358 struct bss_txcmd_tlv {
359 __le16 tag;
360 __le16 len;
361@@ -954,7 +975,10 @@ enum {
362 sizeof(struct bss_bcn_content_tlv) + \
363 4 + MT_TXD_SIZE + \
364 sizeof(struct bss_bcn_cntdwn_tlv) + \
365- sizeof(struct bss_bcn_mbss_tlv))
366+ sizeof(struct bss_bcn_mbss_tlv) + \
367+ sizeof(struct bss_bcn_crit_update_tlv) + \
368+ sizeof(struct bss_bcn_sta_prof_cntdwn_tlv)) \
369+
370 #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \
371 MT7996_BEACON_UPDATE_SIZE)
372
373diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800374index b8699b65..4815cf7b 100644
developer05f3b2b2024-08-19 19:17:34 +0800375--- a/mt7996/mt7996.h
376+++ b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800377@@ -352,6 +352,7 @@ struct mt7996_bss_conf {
developer05f3b2b2024-08-19 19:17:34 +0800378
379 u8 link_id;
380 u8 own_mld_id;
381+ u8 bpcc;
382 };
383
384 struct mt7996_vif {
developerd0c89452024-10-11 16:53:27 +0800385@@ -366,6 +367,9 @@ struct mt7996_vif {
developer05f3b2b2024-08-19 19:17:34 +0800386 u8 group_mld_id;
387 u8 mld_remap_id;
388
389+ u8 cs_link_id;
390+ u16 cs_ready_links;
391+
392 u8 band_to_link[__MT_MAX_BAND];
393
394 /* for beacon monitoring */
395--
developerd0c89452024-10-11 16:53:27 +08003962.45.2
developer05f3b2b2024-08-19 19:17:34 +0800397