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