blob: 452ba1f20e3d9c9b3e410011c7f1205d08fe6e58 [file] [log] [blame]
developer05f3b2b2024-08-19 19:17:34 +08001From c2213afbe5f0c0b36ba7fb19c2bd9f04cea01cc9 Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: Shayne Chen <shayne.chen@mediatek.com>
3Date: Fri, 3 Nov 2023 21:44:45 +0800
developer05f3b2b2024-08-19 19:17:34 +08004Subject: [PATCH 087/199] mtk: mt76: mt7996: implement and switch to hw scan
developer66e89bc2024-04-23 14:50:01 +08005 callbacks
6
7To support MLO, hw_scan callbacks are mandatory. However, the
8firmware of AP-segment doesn't support hw_scan commands, so we need
9to implement it in the driver.
10This is a preliminary patch to add MLO support for mt7996 chipsets.
11
12If the cfg80211_scan_request contains an unicast BSSID, the probe
13request should be unicast.
14This works for ML probe request, which should be unicast.
15
developer66e89bc2024-04-23 14:50:01 +080016Co-developed-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
17Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
developer05f3b2b2024-08-19 19:17:34 +080018Co-developed-by: Peter Chiu <chui-hao.chiu@mediatek.com>
19Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
developer66e89bc2024-04-23 14:50:01 +080020Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
21---
22 mac80211.c | 3 +-
23 mt76.h | 2 +
24 mt7996/init.c | 5 ++
25 mt7996/mac.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
26 mt7996/main.c | 95 ++++++++++++++++++++++++++++----
27 mt7996/mcu.c | 3 +-
28 mt7996/mt7996.h | 11 +++-
29 7 files changed, 248 insertions(+), 12 deletions(-)
30
31diff --git a/mac80211.c b/mac80211.c
developer05f3b2b2024-08-19 19:17:34 +080032index 3e054d9d..032a13a5 100644
developer66e89bc2024-04-23 14:50:01 +080033--- a/mac80211.c
34+++ b/mac80211.c
developer05f3b2b2024-08-19 19:17:34 +080035@@ -820,7 +820,7 @@ bool mt76_has_tx_pending(struct mt76_phy *phy)
developer66e89bc2024-04-23 14:50:01 +080036 }
37 EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
38
39-static struct mt76_channel_state *
40+struct mt76_channel_state *
41 mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
42 {
43 struct mt76_sband *msband;
developer05f3b2b2024-08-19 19:17:34 +080044@@ -836,6 +836,7 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
developer66e89bc2024-04-23 14:50:01 +080045 idx = c - &msband->sband.channels[0];
46 return &msband->chan[idx];
47 }
48+EXPORT_SYMBOL_GPL(mt76_channel_state);
49
50 void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
51 {
52diff --git a/mt76.h b/mt76.h
developer05f3b2b2024-08-19 19:17:34 +080053index 8f3541e2..6a7752ef 100644
developer66e89bc2024-04-23 14:50:01 +080054--- a/mt76.h
55+++ b/mt76.h
developer05f3b2b2024-08-19 19:17:34 +080056@@ -1469,6 +1469,8 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
developer66e89bc2024-04-23 14:50:01 +080057 enum ieee80211_frame_release_type reason,
58 bool more_data);
59 bool mt76_has_tx_pending(struct mt76_phy *phy);
60+struct mt76_channel_state *
61+mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c);
62 void mt76_set_channel(struct mt76_phy *phy);
63 void mt76_update_survey(struct mt76_phy *phy);
64 void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time);
65diff --git a/mt7996/init.c b/mt7996/init.c
developer05f3b2b2024-08-19 19:17:34 +080066index 1e4e6e78..2b396d94 100644
developer66e89bc2024-04-23 14:50:01 +080067--- a/mt7996/init.c
68+++ b/mt7996/init.c
developer05f3b2b2024-08-19 19:17:34 +080069@@ -459,6 +459,9 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
developer66e89bc2024-04-23 14:50:01 +080070
71 wiphy->available_antennas_rx = phy->mt76->antenna_mask;
72 wiphy->available_antennas_tx = phy->mt76->antenna_mask;
73+
74+ wiphy->max_scan_ssids = 4;
75+ wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
76 }
77
78 static void
developer05f3b2b2024-08-19 19:17:34 +080079@@ -679,6 +682,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
developer66e89bc2024-04-23 14:50:01 +080080 mphy->dev->phys[band] = mphy;
81
82 INIT_DELAYED_WORK(&mphy->mac_work, mt7996_mac_work);
83+ INIT_DELAYED_WORK(&phy->scan_work, mt7996_scan_work);
84
85 ret = mt7996_eeprom_parse_hw_cap(dev, phy);
86 if (ret)
87@@ -1574,6 +1578,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
88 dev->mt76.phy.priv = &dev->phy;
89 INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
90 INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
91+ INIT_DELAYED_WORK(&dev->phy.scan_work, mt7996_scan_work);
92 INIT_DELAYED_WORK(&dev->scs_work, mt7996_mcu_scs_sta_poll);
93 INIT_LIST_HEAD(&dev->sta_rc_list);
94 INIT_LIST_HEAD(&dev->twt_list);
95diff --git a/mt7996/mac.c b/mt7996/mac.c
developer05f3b2b2024-08-19 19:17:34 +080096index 564f080d..7578cbb0 100644
developer66e89bc2024-04-23 14:50:01 +080097--- a/mt7996/mac.c
98+++ b/mt7996/mac.c
99@@ -2693,3 +2693,144 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
100 dev->twt.table_mask &= ~BIT(flow->table_id);
101 dev->twt.n_agrt--;
102 }
103+
104+static void
105+mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
106+ const u8 *dst)
107+{
108+ struct ieee80211_hw *hw = phy->mt76->hw;
109+ struct cfg80211_scan_request *req = phy->scan_req;
110+ struct ieee80211_vif *vif = phy->scan_vif;
111+ struct mt7996_vif *mvif;
112+ struct mt76_wcid *wcid;
113+ struct ieee80211_tx_info *info;
114+ struct sk_buff *skb;
115+
116+ if (!req || !vif)
117+ return;
118+
119+ mvif = (struct mt7996_vif *)vif->drv_priv;
120+ wcid = &mvif->sta.wcid;
121+
122+ skb = ieee80211_probereq_get(hw, vif->addr,
123+ ssid->ssid, ssid->ssid_len, req->ie_len);
124+ if (!skb)
125+ return;
126+
127+ if (is_unicast_ether_addr(dst)) {
128+ struct ieee80211_hdr_3addr *hdr =
129+ (struct ieee80211_hdr_3addr *)skb->data;
130+ memcpy(hdr->addr1, dst, ETH_ALEN);
131+ memcpy(hdr->addr3, dst, ETH_ALEN);
132+ }
133+
134+ info = IEEE80211_SKB_CB(skb);
135+ if (req->no_cck)
136+ info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
137+
138+ if (req->ie_len)
139+ skb_put_data(skb, req->ie, req->ie_len);
140+
141+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
142+
143+ rcu_read_lock();
144+ if (!ieee80211_tx_prepare_skb(hw, vif, skb,
145+ phy->scan_chan->band,
146+ NULL)) {
147+ rcu_read_unlock();
148+ ieee80211_free_txskb(hw, skb);
149+ return;
150+ }
151+
152+ local_bh_disable();
153+ mt76_tx(phy->mt76, NULL, wcid, skb);
154+ local_bh_enable();
155+
156+ rcu_read_unlock();
157+}
158+
159+void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted)
160+{
161+ struct cfg80211_scan_info info = {
162+ .aborted = aborted,
163+ };
164+
165+ ieee80211_scan_completed(phy->mt76->hw, &info);
166+ phy->scan_chan = NULL;
167+ phy->scan_req = NULL;
168+ phy->scan_vif = NULL;
169+ clear_bit(MT76_SCANNING, &phy->mt76->state);
170+}
171+
172+static void mt7996_scan_check_sta(void *data, struct ieee80211_sta *sta)
173+{
174+ bool *has_sta = data;
175+
176+ if (*has_sta)
177+ return;
178+ *has_sta = true;
179+}
180+
181+void mt7996_scan_work(struct work_struct *work)
182+{
183+ struct mt7996_phy *phy = container_of(work, struct mt7996_phy, scan_work.work);
184+ struct ieee80211_hw *hw = phy->mt76->hw;
185+ struct cfg80211_scan_request *req = phy->scan_req;
186+ struct cfg80211_chan_def chandef = {};
187+ int duration;
188+ bool has_sta = false, active_scan = false;
189+
190+ mutex_lock(&phy->dev->mt76.mutex);
191+ if (phy->scan_chan_idx >= req->n_channels) {
192+ mt7996_scan_complete(phy, false);
193+ mutex_unlock(&phy->dev->mt76.mutex);
194+
195+ mt7996_set_channel(phy, &hw->conf.chandef);
196+
197+ return;
198+ }
199+
200+ ieee80211_iterate_stations_atomic(hw, mt7996_scan_check_sta, &has_sta);
201+
202+ /* go back to operating channel */
203+ if (has_sta && phy->scan_chan) {
204+ phy->scan_chan = NULL;
205+ mutex_unlock(&phy->dev->mt76.mutex);
206+
207+ mt7996_set_channel(phy, &phy->mt76->chandef);
208+
209+ ieee80211_queue_delayed_work(hw, &phy->scan_work, HZ / 10);
210+
211+ return;
212+ }
213+
214+ wiphy_info(hw->wiphy, "hw scan %d MHz\n",
215+ req->channels[phy->scan_chan_idx]->center_freq);
216+
217+ phy->scan_chan = req->channels[phy->scan_chan_idx++];
218+
219+ if (!req->n_ssids ||
220+ (phy->scan_chan->flags & (IEEE80211_CHAN_NO_IR |
221+ IEEE80211_CHAN_RADAR))) {
222+ duration = HZ / 9; /* ~110 ms */
223+ } else {
224+ duration = HZ / 16; /* ~60 ms */
225+ active_scan = true;
226+ }
227+
228+ cfg80211_chandef_create(&chandef, phy->scan_chan, NL80211_CHAN_HT20);
229+ mutex_unlock(&phy->dev->mt76.mutex);
230+
231+ mt7996_set_channel(phy, &chandef);
232+
233+ if (active_scan) {
234+ int i;
235+
236+ mutex_lock(&phy->dev->mt76.mutex);
237+ for (i = 0; i < req->n_ssids; i++)
238+ mt7996_scan_send_probe(phy, &req->ssids[i], req->bssid);
239+ mutex_unlock(&phy->dev->mt76.mutex);
240+ }
241+
242+ ieee80211_queue_delayed_work(hw, &phy->scan_work, duration);
243+}
244diff --git a/mt7996/main.c b/mt7996/main.c
developer05f3b2b2024-08-19 19:17:34 +0800245index a37aac43..c640fb61 100644
developer66e89bc2024-04-23 14:50:01 +0800246--- a/mt7996/main.c
247+++ b/mt7996/main.c
248@@ -312,6 +312,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
249 struct mt7996_phy *phy = mt7996_hw_phy(hw);
250 int idx = msta->wcid.idx;
251
252+ cancel_delayed_work_sync(&phy->scan_work);
253+
254 mt7996_mcu_add_sta(dev, vif, NULL, false, false);
255 mt7996_mcu_add_bss_info(phy, vif, false);
256
257@@ -323,6 +325,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
258 rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
259
260 mutex_lock(&dev->mt76.mutex);
261+
262+ if (test_bit(MT76_SCANNING, &phy->mt76->state))
263+ mt7996_scan_complete(phy, true);
264+
265 dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
266 phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
267 mutex_unlock(&dev->mt76.mutex);
268@@ -335,7 +341,33 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
269 mt76_wcid_cleanup(&dev->mt76, &msta->wcid);
270 }
271
272-int mt7996_set_channel(struct mt7996_phy *phy)
273+static void ___mt7996_set_channel(struct mt7996_phy *phy,
274+ struct cfg80211_chan_def *chandef)
275+{
276+ struct mt76_dev *mdev = phy->mt76->dev;
277+ struct mt76_phy *mphy = phy->mt76;
278+ bool offchannel = phy->scan_chan != NULL;
279+ int timeout = HZ / 5;
280+
281+ wait_event_timeout(mdev->tx_wait, !mt76_has_tx_pending(mphy), timeout);
282+ mt76_update_survey(mphy);
283+
284+ if (mphy->chandef.chan->center_freq != chandef->chan->center_freq ||
285+ mphy->chandef.width != chandef->width)
286+ mphy->dfs_state = MT_DFS_STATE_UNKNOWN;
287+
288+ mphy->chandef = *chandef;
289+ mphy->chan_state = mt76_channel_state(mphy, chandef->chan);
290+
291+ if (!offchannel)
292+ mphy->main_chan = chandef->chan;
293+
294+ if (chandef->chan != mphy->main_chan)
295+ memset(mphy->chan_state, 0, sizeof(*mphy->chan_state));
296+}
297+
298+static int __mt7996_set_channel(struct mt7996_phy *phy,
299+ struct cfg80211_chan_def *chandef)
300 {
301 struct mt7996_dev *dev = phy->dev;
302 int ret;
303@@ -345,7 +377,7 @@ int mt7996_set_channel(struct mt7996_phy *phy)
304 mutex_lock(&dev->mt76.mutex);
305 set_bit(MT76_RESET, &phy->mt76->state);
306
307- mt76_set_channel(phy->mt76);
308+ ___mt7996_set_channel(phy, chandef);
309
310 if (dev->cal) {
311 ret = mt7996_mcu_apply_tx_dpd(phy);
developer05f3b2b2024-08-19 19:17:34 +0800312@@ -385,6 +417,19 @@ out:
developer66e89bc2024-04-23 14:50:01 +0800313 return ret;
314 }
315
316+int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef)
317+{
318+ int ret;
319+
320+ ieee80211_stop_queues(phy->mt76->hw);
321+ ret = __mt7996_set_channel(phy, chandef);
322+ if (ret)
323+ return ret;
324+ ieee80211_wake_queues(phy->mt76->hw);
325+
326+ return 0;
327+}
328+
329 static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
330 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
331 struct ieee80211_key_conf *key)
developer05f3b2b2024-08-19 19:17:34 +0800332@@ -481,11 +526,7 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
developer66e89bc2024-04-23 14:50:01 +0800333 if (ret)
334 return ret;
335
336- ieee80211_stop_queues(hw);
337- ret = mt7996_set_channel(phy);
338- if (ret)
339- return ret;
340- ieee80211_wake_queues(hw);
341+ mt7996_set_channel(phy, &hw->conf.chandef);
342 }
343
344 if (changed & (IEEE80211_CONF_CHANGE_POWER |
developer05f3b2b2024-08-19 19:17:34 +0800345@@ -1652,6 +1693,42 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
developer66e89bc2024-04-23 14:50:01 +0800346
347 #endif
348
349+static int
350+mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
351+ struct ieee80211_scan_request *hw_req)
352+{
353+ struct cfg80211_scan_request *req = &hw_req->req;
354+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
355+
356+ mutex_lock(&phy->dev->mt76.mutex);
357+ if (WARN_ON(phy->scan_req || phy->scan_chan)) {
358+ mutex_unlock(&phy->dev->mt76.mutex);
359+ return -EBUSY;
360+ }
361+
362+ set_bit(MT76_SCANNING, &phy->mt76->state);
363+ phy->scan_req = req;
364+ phy->scan_vif = vif;
365+ phy->scan_chan_idx = 0;
366+ mutex_unlock(&phy->dev->mt76.mutex);
367+
368+ ieee80211_queue_delayed_work(hw, &phy->scan_work, 0);
369+
370+ return 0;
371+}
372+
373+static void
374+mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
375+{
376+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
377+
378+ cancel_delayed_work_sync(&phy->scan_work);
379+
380+ mutex_lock(&phy->dev->mt76.mutex);
381+ mt7996_scan_complete(phy, true);
382+ mutex_unlock(&phy->dev->mt76.mutex);
383+}
384+
385 const struct ieee80211_ops mt7996_ops = {
developer05f3b2b2024-08-19 19:17:34 +0800386 .add_chanctx = ieee80211_emulate_add_chanctx,
387 .remove_chanctx = ieee80211_emulate_remove_chanctx,
388@@ -1674,8 +1751,8 @@ const struct ieee80211_ops mt7996_ops = {
developer66e89bc2024-04-23 14:50:01 +0800389 .ampdu_action = mt7996_ampdu_action,
390 .set_rts_threshold = mt7996_set_rts_threshold,
391 .wake_tx_queue = mt76_wake_tx_queue,
392- .sw_scan_start = mt76_sw_scan,
393- .sw_scan_complete = mt76_sw_scan_complete,
394+ .hw_scan = mt7996_hw_scan,
395+ .cancel_hw_scan = mt7996_cancel_hw_scan,
396 .release_buffered_frames = mt76_release_buffered_frames,
397 .get_txpower = mt76_get_txpower,
398 .channel_switch_beacon = mt7996_channel_switch_beacon,
399diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer05f3b2b2024-08-19 19:17:34 +0800400index 8cc907f9..214c157c 100644
developer66e89bc2024-04-23 14:50:01 +0800401--- a/mt7996/mcu.c
402+++ b/mt7996/mcu.c
developer05f3b2b2024-08-19 19:17:34 +0800403@@ -3778,7 +3778,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
developer66e89bc2024-04-23 14:50:01 +0800404 if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
405 req.switch_reason = CH_SWITCH_NORMAL;
406 else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
407- phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
408+ phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE ||
409+ phy->scan_chan)
410 req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
411 else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
412 NL80211_IFTYPE_AP))
413diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer05f3b2b2024-08-19 19:17:34 +0800414index d5162885..f94cb496 100644
developer66e89bc2024-04-23 14:50:01 +0800415--- a/mt7996/mt7996.h
416+++ b/mt7996/mt7996.h
developer05f3b2b2024-08-19 19:17:34 +0800417@@ -459,6 +459,13 @@ struct mt7996_phy {
developer66e89bc2024-04-23 14:50:01 +0800418 u8 pp_mode;
419 u16 punct_bitmap;
420
421+ /* for hw_scan */
422+ struct delayed_work scan_work;
423+ struct ieee80211_channel *scan_chan;
424+ struct cfg80211_scan_request *scan_req;
425+ struct ieee80211_vif *scan_vif;
426+ int scan_chan_idx;
427+
428 struct mt7996_scs_ctrl scs_ctrl;
429 u32 red_drop;
430
developer05f3b2b2024-08-19 19:17:34 +0800431@@ -807,7 +814,7 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
developer66e89bc2024-04-23 14:50:01 +0800432 struct ieee80211_he_obss_pd *he_obss_pd);
433 int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
434 struct ieee80211_sta *sta, bool changed);
435-int mt7996_set_channel(struct mt7996_phy *phy);
436+int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
437 int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
438 int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif);
439 int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
developer05f3b2b2024-08-19 19:17:34 +0800440@@ -965,6 +972,8 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
developer66e89bc2024-04-23 14:50:01 +0800441 struct sk_buff *skb, u32 *info);
442 bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
443 void mt7996_stats_work(struct work_struct *work);
444+void mt7996_scan_work(struct work_struct *work);
445+void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted);
446 int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
447 int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);
448 void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy);
449--
developer9237f442024-06-14 17:13:04 +08004502.18.0
developer66e89bc2024-04-23 14:50:01 +0800451