blob: 0a5ab02dd4f83ff4174e4bf8c542a4523a024e79 [file] [log] [blame]
developerd0c89452024-10-11 16:53:27 +08001From f6889bcb95884df285d628c93b78fe28a5008262 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
developerd0c89452024-10-11 16:53:27 +08004Subject: [PATCH 076/223] mtk: 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
developerd0c89452024-10-11 16:53:27 +080011Change-Id: Ie4530a3bc2ac9e51045184d5aecca14118177042
developer66e89bc2024-04-23 14:50:01 +080012Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
13Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
14Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
15---
16 mt7996/init.c | 22 ++++++
17 mt7996/mac.c | 10 ++-
18 mt7996/main.c | 178 ++++++++++++++++++++++++++++++++++++++++++++----
19 mt7996/mcu.c | 2 +-
20 mt7996/mt7996.h | 17 +++++
21 5 files changed, 211 insertions(+), 18 deletions(-)
22
23diff --git a/mt7996/init.c b/mt7996/init.c
developerd0c89452024-10-11 16:53:27 +080024index a188fa1d..7afbd46a 100644
developer66e89bc2024-04-23 14:50:01 +080025--- a/mt7996/init.c
26+++ b/mt7996/init.c
developer05f3b2b2024-08-19 19:17:34 +080027@@ -384,6 +384,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
developer66e89bc2024-04-23 14:50:01 +080028
29 hw->sta_data_size = sizeof(struct mt7996_sta);
30 hw->vif_data_size = sizeof(struct mt7996_vif);
31+ hw->chanctx_data_size = sizeof(struct mt7996_chanctx);
32
33 wiphy->iface_combinations = if_comb;
34 wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
developer05f3b2b2024-08-19 19:17:34 +080035@@ -419,6 +420,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
developer66e89bc2024-04-23 14:50:01 +080036 ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
37 ieee80211_hw_set(hw, WANT_MONITOR_VIF);
38 ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
39+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
40
41 hw->max_tx_fragments = 4;
42
developer05f3b2b2024-08-19 19:17:34 +080043@@ -639,6 +641,22 @@ static int mt7996_vow_init(struct mt7996_phy *phy)
developer66e89bc2024-04-23 14:50:01 +080044 return mt7996_mcu_set_vow_feature_ctrl(phy);
45 }
46
47+static void mt7996_init_chanctx(struct mt7996_phy *phy)
48+{
49+ struct ieee80211_supported_band *sband;
50+ struct ieee80211_channel *chan;
51+
52+ if (phy->mt76->band_idx == MT_BAND2)
53+ sband = &phy->mt76->sband_6g.sband;
54+ else if (phy->mt76->band_idx == MT_BAND1)
55+ sband = &phy->mt76->sband_5g.sband;
56+ else
57+ sband = &phy->mt76->sband_2g.sband;
58+
59+ chan = &sband->channels[0];
60+ cfg80211_chandef_create(&phy->mt76->chandef, chan, NL80211_CHAN_HT20);
61+}
62+
63 static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
64 enum mt76_band_id band)
65 {
developer05f3b2b2024-08-19 19:17:34 +080066@@ -722,6 +740,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
developer66e89bc2024-04-23 14:50:01 +080067 if (ret)
68 goto error;
69
70+ mt7996_init_chanctx(phy);
71+
72 ret = mt7996_thermal_init(phy);
73 if (ret)
74 goto error;
developerd0c89452024-10-11 16:53:27 +080075@@ -1629,6 +1649,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +080076 if (ret)
77 return ret;
78
79+ mt7996_init_chanctx(&dev->phy);
80+
81 ret = mt7996_thermal_init(&dev->phy);
82 if (ret)
83 return ret;
84diff --git a/mt7996/mac.c b/mt7996/mac.c
developerd0c89452024-10-11 16:53:27 +080085index 5c29fe7f..7cfc25ba 100644
developer66e89bc2024-04-23 14:50:01 +080086--- a/mt7996/mac.c
87+++ b/mt7996/mac.c
developerd0c89452024-10-11 16:53:27 +080088@@ -2797,7 +2797,10 @@ void mt7996_scan_work(struct work_struct *work)
developer66e89bc2024-04-23 14:50:01 +080089 mt7996_scan_complete(phy, false);
90 mutex_unlock(&phy->dev->mt76.mutex);
91
92- mt7996_set_channel(phy, &hw->conf.chandef);
93+ if (phy->chanctx)
94+ mt7996_set_channel(phy, &phy->chanctx->chandef);
95+ else
96+ mt7996_set_channel(phy, &phy->mt76->chandef);
97
98 return;
99 }
developerd0c89452024-10-11 16:53:27 +0800100@@ -2809,7 +2812,10 @@ void mt7996_scan_work(struct work_struct *work)
developer66e89bc2024-04-23 14:50:01 +0800101 phy->scan_chan = NULL;
102 mutex_unlock(&phy->dev->mt76.mutex);
103
104- mt7996_set_channel(phy, &phy->mt76->chandef);
105+ if (phy->chanctx)
106+ mt7996_set_channel(phy, &phy->chanctx->chandef);
107+ else
108+ mt7996_set_channel(phy, &phy->mt76->chandef);
109
110 ieee80211_queue_delayed_work(hw, &phy->scan_work, HZ / 10);
111
112diff --git a/mt7996/main.c b/mt7996/main.c
developerd0c89452024-10-11 16:53:27 +0800113index 475763e4..cbd64681 100644
developer66e89bc2024-04-23 14:50:01 +0800114--- a/mt7996/main.c
115+++ b/mt7996/main.c
116@@ -76,6 +76,11 @@ int mt7996_run(struct ieee80211_hw *hw)
117 if (ret)
118 goto out;
119
120+ /* set a parking channel */
121+ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
122+ if (ret)
123+ goto out;
124+
125 ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
126 if (ret)
127 goto out;
developerd0c89452024-10-11 16:53:27 +0800128@@ -508,21 +513,6 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
developer66e89bc2024-04-23 14:50:01 +0800129 struct mt7996_phy *phy = mt7996_hw_phy(hw);
130 int ret;
131
132- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
133- if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
134- ret = mt7996_mcu_edcca_enable(phy, true);
135- if (ret)
136- return ret;
137- }
138-
139- ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE,
140- phy->mt76->chandef.punctured);
141- if (ret)
142- return ret;
143-
144- mt7996_set_channel(phy, &hw->conf.chandef);
145- }
146-
147 if (changed & (IEEE80211_CONF_CHANGE_POWER |
148 IEEE80211_CONF_CHANGE_CHANNEL)) {
149 ret = mt7996_mcu_set_txpower_sku(phy);
developerd0c89452024-10-11 16:53:27 +0800150@@ -1723,6 +1713,158 @@ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
developer66e89bc2024-04-23 14:50:01 +0800151 mutex_unlock(&phy->dev->mt76.mutex);
152 }
153
154+static int
155+mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
156+{
157+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
158+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
159+ int ret;
160+
161+ wiphy_info(hw->wiphy, "%s: add %u\n", __func__, conf->def.chan->hw_value);
162+ mutex_lock(&phy->dev->mt76.mutex);
163+
164+ if (ctx->assigned) {
165+ mutex_unlock(&phy->dev->mt76.mutex);
166+ return -ENOSPC;
167+ }
168+
169+ ctx->assigned = true;
170+ ctx->chandef = conf->def;
171+ ctx->phy = phy;
172+ if (phy->chanctx) {
173+ mutex_unlock(&phy->dev->mt76.mutex);
174+ return 0;
175+ }
176+
177+ phy->chanctx = ctx;
178+ mutex_unlock(&phy->dev->mt76.mutex);
179+
180+ if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
181+ ret = mt7996_mcu_edcca_enable(phy, true);
182+ if (ret)
183+ return ret;
184+ }
185+
186+ ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE, ctx->chandef.punctured);
187+ if (ret)
188+ return ret;
189+
190+ return mt7996_set_channel(phy, &ctx->chandef);
191+}
192+
193+static void
194+mt7996_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
195+{
196+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
197+ struct mt7996_phy *phy = ctx->phy;
198+
199+ wiphy_info(hw->wiphy, "%s: remove %u\n", __func__, conf->def.chan->hw_value);
200+ cancel_delayed_work_sync(&phy->scan_work);
201+ cancel_delayed_work_sync(&phy->mt76->mac_work);
202+
203+ mutex_lock(&phy->dev->mt76.mutex);
204+ ctx->assigned = false;
205+ if (ctx == phy->chanctx)
206+ phy->chanctx = NULL;
207+ mutex_unlock(&phy->dev->mt76.mutex);
208+}
209+
210+static void
211+mt7996_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf,
212+ u32 changed)
213+{
214+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
215+ struct mt7996_phy *phy = ctx->phy;
216+
217+ wiphy_info(hw->wiphy, "%s: change %u, 0x%x\n", __func__, conf->def.chan->hw_value, changed);
218+ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
219+ ctx->chandef = conf->def;
220+
221+ mt7996_set_channel(phy, &ctx->chandef);
222+ }
223+}
224+
225+static int
226+mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
227+ struct ieee80211_bss_conf *link_conf,
228+ struct ieee80211_chanctx_conf *conf)
229+{
230+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
231+ struct mt7996_phy *phy = ctx->phy;
232+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
233+
234+ wiphy_info(hw->wiphy, "Assign VIF (addr: %pM, type: %d, link_id: %d) to channel context: %d MHz\n",
235+ vif->addr, vif->type, link_conf->link_id,
236+ conf->def.chan->center_freq);
237+
238+ mutex_lock(&phy->dev->mt76.mutex);
239+
240+ mvif->chanctx = ctx;
241+ ctx->nbss_assigned++;
242+
243+ mutex_unlock(&phy->dev->mt76.mutex);
244+
245+ return 0;
246+}
247+
248+static void
249+mt7996_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
250+ struct ieee80211_bss_conf *link_conf,
251+ struct ieee80211_chanctx_conf *conf)
252+{
253+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
254+ struct mt7996_phy *phy = ctx->phy;
255+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
256+
257+ wiphy_info(hw->wiphy, "Remove VIF (addr: %pM, type: %d, link_id: %d) from channel context: %d MHz\n",
258+ vif->addr, vif->type, link_conf->link_id,
259+ conf->def.chan->center_freq);
260+ cancel_delayed_work_sync(&phy->scan_work);
261+
262+ mutex_lock(&phy->dev->mt76.mutex);
263+
264+ if (test_bit(MT76_SCANNING, &phy->mt76->state))
265+ mt7996_scan_complete(phy, true);
266+
267+ mvif->chanctx = NULL;
268+ ctx->nbss_assigned--;
269+
270+ mutex_unlock(&phy->dev->mt76.mutex);
271+}
272+
273+static int
274+mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
275+ struct ieee80211_vif_chanctx_switch *vifs,
276+ int n_vifs,
277+ enum ieee80211_chanctx_switch_mode mode)
278+{
279+ struct mt7996_chanctx *old_ctx = mt7996_chanctx_get(vifs->old_ctx);
280+ struct mt7996_chanctx *new_ctx = mt7996_chanctx_get(vifs->new_ctx);
281+ struct mt7996_phy *phy = old_ctx->phy;
282+
283+ 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);
284+
285+ if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
286+ new_ctx->nbss_assigned += n_vifs;
287+ return 0;
288+ }
289+
290+ if (WARN_ON(old_ctx != phy->chanctx))
291+ return -EINVAL;
292+
293+ mutex_lock(&phy->dev->mt76.mutex);
294+
295+ phy->chanctx = new_ctx;
296+ new_ctx->assigned = true;
297+ new_ctx->chandef = vifs->new_ctx->def;
298+ new_ctx->phy = phy;
299+ new_ctx->nbss_assigned += n_vifs;
300+
301+ mutex_unlock(&phy->dev->mt76.mutex);
302+
303+ return mt7996_set_channel(phy, &new_ctx->chandef);
304+}
305+
306 const struct ieee80211_ops mt7996_ops = {
developer05f3b2b2024-08-19 19:17:34 +0800307 .add_chanctx = ieee80211_emulate_add_chanctx,
308 .remove_chanctx = ieee80211_emulate_remove_chanctx,
developerd0c89452024-10-11 16:53:27 +0800309@@ -1777,4 +1919,10 @@ const struct ieee80211_ops mt7996_ops = {
developer66e89bc2024-04-23 14:50:01 +0800310 .net_fill_forward_path = mt7996_net_fill_forward_path,
311 .net_setup_tc = mt76_wed_net_setup_tc,
312 #endif
313+ .add_chanctx = mt7996_add_chanctx,
314+ .remove_chanctx = mt7996_remove_chanctx,
315+ .change_chanctx = mt7996_change_chanctx,
316+ .assign_vif_chanctx = mt7996_assign_vif_chanctx,
317+ .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
318+ .switch_vif_chanctx = mt7996_switch_vif_chanctx,
319 };
320diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800321index 746fc223..ba53c3fc 100644
developer66e89bc2024-04-23 14:50:01 +0800322--- a/mt7996/mcu.c
323+++ b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800324@@ -5322,7 +5322,7 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap)
developer66e89bc2024-04-23 14:50:01 +0800325 .bitmap = cpu_to_le16(bitmap),
326 };
327
328- if (phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ ||
329+ if (phy->chanctx->chandef.chan->band == NL80211_BAND_2GHZ ||
330 mode > PP_USR_MODE)
331 return 0;
332
333diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800334index 87b166aa..07790257 100644
developer66e89bc2024-04-23 14:50:01 +0800335--- a/mt7996/mt7996.h
336+++ b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800337@@ -334,6 +334,8 @@ struct mt7996_vif {
developer66e89bc2024-04-23 14:50:01 +0800338
339 struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
340 struct cfg80211_bitrate_mask bitrate_mask;
341+
342+ struct mt7996_chanctx *chanctx;
343 };
344
345 /* crash-dump */
developerd0c89452024-10-11 16:53:27 +0800346@@ -423,6 +425,14 @@ struct mt7996_rro_ba_session {
developer66e89bc2024-04-23 14:50:01 +0800347 u32 last_in_rxtime :12;
348 };
349
350+struct mt7996_chanctx {
351+ struct cfg80211_chan_def chandef;
352+ struct mt7996_phy *phy;
353+
354+ bool assigned;
355+ u8 nbss_assigned;
356+};
357+
358 struct mt7996_phy {
359 struct mt76_phy *mt76;
360 struct mt7996_dev *dev;
developerd0c89452024-10-11 16:53:27 +0800361@@ -466,6 +476,7 @@ struct mt7996_phy {
developer66e89bc2024-04-23 14:50:01 +0800362 struct cfg80211_scan_request *scan_req;
363 struct ieee80211_vif *scan_vif;
364 int scan_chan_idx;
365+ struct mt7996_chanctx *chanctx;
366
367 struct mt7996_scs_ctrl scs_ctrl;
368 u32 red_drop;
developerd0c89452024-10-11 16:53:27 +0800369@@ -757,6 +768,12 @@ mt7996_has_background_radar(struct mt7996_dev *dev)
370 return true;
developer66e89bc2024-04-23 14:50:01 +0800371 }
372
373+static inline struct mt7996_chanctx *
374+mt7996_chanctx_get(struct ieee80211_chanctx_conf *ctx)
375+{
376+ return (struct mt7996_chanctx *)&ctx->drv_priv;
377+}
378+
379 extern const struct ieee80211_ops mt7996_ops;
380 extern struct pci_driver mt7996_pci_driver;
381 extern struct pci_driver mt7996_hif_driver;
382--
developerd0c89452024-10-11 16:53:27 +08003832.45.2
developer66e89bc2024-04-23 14:50:01 +0800384