blob: 0e99f390399fa194ca2739cd2c708b20cb328ccb [file] [log] [blame]
developer9237f442024-06-14 17:13:04 +08001From d225140776409dcf5b526034682768803e551dbb Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: Shayne Chen <shayne.chen@mediatek.com>
3Date: Mon, 6 Nov 2023 16:17:11 +0800
developer9237f442024-06-14 17:13:04 +08004Subject: [PATCH 083/116] wifi: mt76: mt7996: implement and switch to chanctx
developer66e89bc2024-04-23 14:50:01 +08005 callbacks
6
7To support MLO, chanctx callbacks are mandatory, since one VIF (MLD) could
8operate on multiple channels (links).
9This is a preliminary patch to add MLO support for mt7996 chipsets.
10
developer66e89bc2024-04-23 14:50:01 +080011Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
12Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
13Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
14---
15 mt7996/init.c | 22 ++++++
16 mt7996/mac.c | 10 ++-
17 mt7996/main.c | 178 ++++++++++++++++++++++++++++++++++++++++++++----
18 mt7996/mcu.c | 2 +-
19 mt7996/mt7996.h | 17 +++++
20 5 files changed, 211 insertions(+), 18 deletions(-)
21
22diff --git a/mt7996/init.c b/mt7996/init.c
developer9237f442024-06-14 17:13:04 +080023index 9523568..6eeec3b 100644
developer66e89bc2024-04-23 14:50:01 +080024--- a/mt7996/init.c
25+++ b/mt7996/init.c
26@@ -382,6 +382,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
27
28 hw->sta_data_size = sizeof(struct mt7996_sta);
29 hw->vif_data_size = sizeof(struct mt7996_vif);
30+ hw->chanctx_data_size = sizeof(struct mt7996_chanctx);
31
32 wiphy->iface_combinations = if_comb;
33 wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
34@@ -417,6 +418,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
35 ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
36 ieee80211_hw_set(hw, WANT_MONITOR_VIF);
37 ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
38+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
39
40 hw->max_tx_fragments = 4;
41
42@@ -637,6 +639,22 @@ static int mt7996_vow_init(struct mt7996_phy *phy)
43 return mt7996_mcu_set_vow_feature_ctrl(phy);
44 }
45
46+static void mt7996_init_chanctx(struct mt7996_phy *phy)
47+{
48+ struct ieee80211_supported_band *sband;
49+ struct ieee80211_channel *chan;
50+
51+ if (phy->mt76->band_idx == MT_BAND2)
52+ sband = &phy->mt76->sband_6g.sband;
53+ else if (phy->mt76->band_idx == MT_BAND1)
54+ sband = &phy->mt76->sband_5g.sband;
55+ else
56+ sband = &phy->mt76->sband_2g.sband;
57+
58+ chan = &sband->channels[0];
59+ cfg80211_chandef_create(&phy->mt76->chandef, chan, NL80211_CHAN_HT20);
60+}
61+
62 static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
63 enum mt76_band_id band)
64 {
65@@ -720,6 +738,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
66 if (ret)
67 goto error;
68
69+ mt7996_init_chanctx(phy);
70+
71 ret = mt7996_thermal_init(phy);
72 if (ret)
73 goto error;
74@@ -1609,6 +1629,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
75 if (ret)
76 return ret;
77
78+ mt7996_init_chanctx(&dev->phy);
79+
80 ret = mt7996_thermal_init(&dev->phy);
81 if (ret)
82 return ret;
83diff --git a/mt7996/mac.c b/mt7996/mac.c
developer9237f442024-06-14 17:13:04 +080084index 4e9dd2c..0879c77 100644
developer66e89bc2024-04-23 14:50:01 +080085--- a/mt7996/mac.c
86+++ b/mt7996/mac.c
87@@ -2785,7 +2785,10 @@ void mt7996_scan_work(struct work_struct *work)
88 mt7996_scan_complete(phy, false);
89 mutex_unlock(&phy->dev->mt76.mutex);
90
91- mt7996_set_channel(phy, &hw->conf.chandef);
92+ if (phy->chanctx)
93+ mt7996_set_channel(phy, &phy->chanctx->chandef);
94+ else
95+ mt7996_set_channel(phy, &phy->mt76->chandef);
96
97 return;
98 }
99@@ -2797,7 +2800,10 @@ void mt7996_scan_work(struct work_struct *work)
100 phy->scan_chan = NULL;
101 mutex_unlock(&phy->dev->mt76.mutex);
102
103- mt7996_set_channel(phy, &phy->mt76->chandef);
104+ if (phy->chanctx)
105+ mt7996_set_channel(phy, &phy->chanctx->chandef);
106+ else
107+ mt7996_set_channel(phy, &phy->mt76->chandef);
108
109 ieee80211_queue_delayed_work(hw, &phy->scan_work, HZ / 10);
110
111diff --git a/mt7996/main.c b/mt7996/main.c
developer9237f442024-06-14 17:13:04 +0800112index 5c1735e..dff0f1f 100644
developer66e89bc2024-04-23 14:50:01 +0800113--- a/mt7996/main.c
114+++ b/mt7996/main.c
115@@ -76,6 +76,11 @@ int mt7996_run(struct ieee80211_hw *hw)
116 if (ret)
117 goto out;
118
119+ /* set a parking channel */
120+ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
121+ if (ret)
122+ goto out;
123+
124 ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
125 if (ret)
126 goto out;
127@@ -510,21 +515,6 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
128 struct mt7996_phy *phy = mt7996_hw_phy(hw);
129 int ret;
130
131- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
132- if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
133- ret = mt7996_mcu_edcca_enable(phy, true);
134- if (ret)
135- return ret;
136- }
137-
138- ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE,
139- phy->mt76->chandef.punctured);
140- if (ret)
141- return ret;
142-
143- mt7996_set_channel(phy, &hw->conf.chandef);
144- }
145-
146 if (changed & (IEEE80211_CONF_CHANGE_POWER |
147 IEEE80211_CONF_CHANGE_CHANNEL)) {
148 ret = mt7996_mcu_set_txpower_sku(phy);
149@@ -1725,6 +1715,158 @@ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
150 mutex_unlock(&phy->dev->mt76.mutex);
151 }
152
153+static int
154+mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
155+{
156+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
157+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
158+ int ret;
159+
160+ wiphy_info(hw->wiphy, "%s: add %u\n", __func__, conf->def.chan->hw_value);
161+ mutex_lock(&phy->dev->mt76.mutex);
162+
163+ if (ctx->assigned) {
164+ mutex_unlock(&phy->dev->mt76.mutex);
165+ return -ENOSPC;
166+ }
167+
168+ ctx->assigned = true;
169+ ctx->chandef = conf->def;
170+ ctx->phy = phy;
171+ if (phy->chanctx) {
172+ mutex_unlock(&phy->dev->mt76.mutex);
173+ return 0;
174+ }
175+
176+ phy->chanctx = ctx;
177+ mutex_unlock(&phy->dev->mt76.mutex);
178+
179+ if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
180+ ret = mt7996_mcu_edcca_enable(phy, true);
181+ if (ret)
182+ return ret;
183+ }
184+
185+ ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE, ctx->chandef.punctured);
186+ if (ret)
187+ return ret;
188+
189+ return mt7996_set_channel(phy, &ctx->chandef);
190+}
191+
192+static void
193+mt7996_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
194+{
195+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
196+ struct mt7996_phy *phy = ctx->phy;
197+
198+ wiphy_info(hw->wiphy, "%s: remove %u\n", __func__, conf->def.chan->hw_value);
199+ cancel_delayed_work_sync(&phy->scan_work);
200+ cancel_delayed_work_sync(&phy->mt76->mac_work);
201+
202+ mutex_lock(&phy->dev->mt76.mutex);
203+ ctx->assigned = false;
204+ if (ctx == phy->chanctx)
205+ phy->chanctx = NULL;
206+ mutex_unlock(&phy->dev->mt76.mutex);
207+}
208+
209+static void
210+mt7996_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf,
211+ u32 changed)
212+{
213+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
214+ struct mt7996_phy *phy = ctx->phy;
215+
216+ wiphy_info(hw->wiphy, "%s: change %u, 0x%x\n", __func__, conf->def.chan->hw_value, changed);
217+ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
218+ ctx->chandef = conf->def;
219+
220+ mt7996_set_channel(phy, &ctx->chandef);
221+ }
222+}
223+
224+static int
225+mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
226+ struct ieee80211_bss_conf *link_conf,
227+ struct ieee80211_chanctx_conf *conf)
228+{
229+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
230+ struct mt7996_phy *phy = ctx->phy;
231+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
232+
233+ wiphy_info(hw->wiphy, "Assign VIF (addr: %pM, type: %d, link_id: %d) to channel context: %d MHz\n",
234+ vif->addr, vif->type, link_conf->link_id,
235+ conf->def.chan->center_freq);
236+
237+ mutex_lock(&phy->dev->mt76.mutex);
238+
239+ mvif->chanctx = ctx;
240+ ctx->nbss_assigned++;
241+
242+ mutex_unlock(&phy->dev->mt76.mutex);
243+
244+ return 0;
245+}
246+
247+static void
248+mt7996_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
249+ struct ieee80211_bss_conf *link_conf,
250+ struct ieee80211_chanctx_conf *conf)
251+{
252+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
253+ struct mt7996_phy *phy = ctx->phy;
254+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
255+
256+ wiphy_info(hw->wiphy, "Remove VIF (addr: %pM, type: %d, link_id: %d) from channel context: %d MHz\n",
257+ vif->addr, vif->type, link_conf->link_id,
258+ conf->def.chan->center_freq);
259+ cancel_delayed_work_sync(&phy->scan_work);
260+
261+ mutex_lock(&phy->dev->mt76.mutex);
262+
263+ if (test_bit(MT76_SCANNING, &phy->mt76->state))
264+ mt7996_scan_complete(phy, true);
265+
266+ mvif->chanctx = NULL;
267+ ctx->nbss_assigned--;
268+
269+ mutex_unlock(&phy->dev->mt76.mutex);
270+}
271+
272+static int
273+mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
274+ struct ieee80211_vif_chanctx_switch *vifs,
275+ int n_vifs,
276+ enum ieee80211_chanctx_switch_mode mode)
277+{
278+ struct mt7996_chanctx *old_ctx = mt7996_chanctx_get(vifs->old_ctx);
279+ struct mt7996_chanctx *new_ctx = mt7996_chanctx_get(vifs->new_ctx);
280+ struct mt7996_phy *phy = old_ctx->phy;
281+
282+ 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);
283+
284+ if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
285+ new_ctx->nbss_assigned += n_vifs;
286+ return 0;
287+ }
288+
289+ if (WARN_ON(old_ctx != phy->chanctx))
290+ return -EINVAL;
291+
292+ mutex_lock(&phy->dev->mt76.mutex);
293+
294+ phy->chanctx = new_ctx;
295+ new_ctx->assigned = true;
296+ new_ctx->chandef = vifs->new_ctx->def;
297+ new_ctx->phy = phy;
298+ new_ctx->nbss_assigned += n_vifs;
299+
300+ mutex_unlock(&phy->dev->mt76.mutex);
301+
302+ return mt7996_set_channel(phy, &new_ctx->chandef);
303+}
304+
305 const struct ieee80211_ops mt7996_ops = {
306 .tx = mt7996_tx,
307 .start = mt7996_start,
308@@ -1775,4 +1917,10 @@ const struct ieee80211_ops mt7996_ops = {
309 .net_fill_forward_path = mt7996_net_fill_forward_path,
310 .net_setup_tc = mt76_wed_net_setup_tc,
311 #endif
312+ .add_chanctx = mt7996_add_chanctx,
313+ .remove_chanctx = mt7996_remove_chanctx,
314+ .change_chanctx = mt7996_change_chanctx,
315+ .assign_vif_chanctx = mt7996_assign_vif_chanctx,
316+ .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
317+ .switch_vif_chanctx = mt7996_switch_vif_chanctx,
318 };
319diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer9237f442024-06-14 17:13:04 +0800320index 9f2d125..5319cc3 100644
developer66e89bc2024-04-23 14:50:01 +0800321--- a/mt7996/mcu.c
322+++ b/mt7996/mcu.c
323@@ -5309,7 +5309,7 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap)
324 .bitmap = cpu_to_le16(bitmap),
325 };
326
327- if (phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ ||
328+ if (phy->chanctx->chandef.chan->band == NL80211_BAND_2GHZ ||
329 mode > PP_USR_MODE)
330 return 0;
331
332diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer9237f442024-06-14 17:13:04 +0800333index fbf1e83..84aafb4 100644
developer66e89bc2024-04-23 14:50:01 +0800334--- a/mt7996/mt7996.h
335+++ b/mt7996/mt7996.h
336@@ -332,6 +332,8 @@ struct mt7996_vif {
337
338 struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
339 struct cfg80211_bitrate_mask bitrate_mask;
340+
341+ struct mt7996_chanctx *chanctx;
342 };
343
344 /* crash-dump */
345@@ -421,6 +423,14 @@ struct mt7996_rro_ba_session {
346 u32 last_in_rxtime :12;
347 };
348
349+struct mt7996_chanctx {
350+ struct cfg80211_chan_def chandef;
351+ struct mt7996_phy *phy;
352+
353+ bool assigned;
354+ u8 nbss_assigned;
355+};
356+
357 struct mt7996_phy {
358 struct mt76_phy *mt76;
359 struct mt7996_dev *dev;
360@@ -464,6 +474,7 @@ struct mt7996_phy {
361 struct cfg80211_scan_request *scan_req;
362 struct ieee80211_vif *scan_vif;
363 int scan_chan_idx;
364+ struct mt7996_chanctx *chanctx;
365
366 struct mt7996_scs_ctrl scs_ctrl;
367 u32 red_drop;
368@@ -752,6 +763,12 @@ mt7996_get_background_radar_cap(struct mt7996_dev *dev)
369 return 1;
370 }
371
372+static inline struct mt7996_chanctx *
373+mt7996_chanctx_get(struct ieee80211_chanctx_conf *ctx)
374+{
375+ return (struct mt7996_chanctx *)&ctx->drv_priv;
376+}
377+
378 extern const struct ieee80211_ops mt7996_ops;
379 extern struct pci_driver mt7996_pci_driver;
380 extern struct pci_driver mt7996_hif_driver;
381--
developer9237f442024-06-14 17:13:04 +08003822.18.0
developer66e89bc2024-04-23 14:50:01 +0800383