[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
1dacd97b [MAC80211][WiFi6][Misc][Fix patch fail]
7c02334a [MAC80211][WiFi7][Misc][Fix build fail because of mt76 version upgradation]
7a073097 [MAC80211][WiFi7][misc][ensure the first MLD bss is bss[0]]
27e2304c [MAC80211][WiFi6][mt76][Refactor due to atenl change]
1e1eb98e [MAC80211][WiFi6/7][app][Add single wiphy support for atenl & iwpriv wrapper]
d4101c33 [MAC80211][WiFi7][mt76][enable lftp for wifi7 r1 cert]
55f5732f [MAC80211][WiFi7][hostapd][set ctrl_interface for all bss]
[Release-log]
Change-Id: I9cad01561c310576a9e5bdc9f1b8eec3025e51d9
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0082-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0082-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch
new file mode 100644
index 0000000..c76593a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0082-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch
@@ -0,0 +1,451 @@
+From 8a1c29f6a9b99d2f3d699fe6100704349406fc4b Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 3 Nov 2023 21:44:45 +0800
+Subject: [PATCH 082/116] wifi: mt76: mt7996: implement and switch to hw scan
+ callbacks
+
+To support MLO, hw_scan callbacks are mandatory. However, the
+firmware of AP-segment doesn't support hw_scan commands, so we need
+to implement it in the driver.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+If the cfg80211_scan_request contains an unicast BSSID, the probe
+request should be unicast.
+This works for ML probe request, which should be unicast.
+
+Co-developed-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Co-developed-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 3 +-
+ mt76.h | 2 +
+ mt7996/init.c | 5 ++
+ mt7996/mac.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c | 95 ++++++++++++++++++++++++++++----
+ mt7996/mcu.c | 3 +-
+ mt7996/mt7996.h | 11 +++-
+ 7 files changed, 248 insertions(+), 12 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 3c2c2af..0ad3f25 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -821,7 +821,7 @@ bool mt76_has_tx_pending(struct mt76_phy *phy)
+ }
+ EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
+
+-static struct mt76_channel_state *
++struct mt76_channel_state *
+ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ {
+ struct mt76_sband *msband;
+@@ -837,6 +837,7 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ idx = c - &msband->sband.channels[0];
+ return &msband->chan[idx];
+ }
++EXPORT_SYMBOL_GPL(mt76_channel_state);
+
+ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
+ {
+diff --git a/mt76.h b/mt76.h
+index 28defd4..8ca7907 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -1477,6 +1477,8 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
+ enum ieee80211_frame_release_type reason,
+ bool more_data);
+ bool mt76_has_tx_pending(struct mt76_phy *phy);
++struct mt76_channel_state *
++mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c);
+ void mt76_set_channel(struct mt76_phy *phy);
+ void mt76_update_survey(struct mt76_phy *phy);
+ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time);
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 768979e..9523568 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -457,6 +457,9 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+
+ wiphy->available_antennas_rx = phy->mt76->antenna_mask;
+ wiphy->available_antennas_tx = phy->mt76->antenna_mask;
++
++ wiphy->max_scan_ssids = 4;
++ wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ }
+
+ static void
+@@ -677,6 +680,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ mphy->dev->phys[band] = mphy;
+
+ INIT_DELAYED_WORK(&mphy->mac_work, mt7996_mac_work);
++ INIT_DELAYED_WORK(&phy->scan_work, mt7996_scan_work);
+
+ ret = mt7996_eeprom_parse_hw_cap(dev, phy);
+ if (ret)
+@@ -1574,6 +1578,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ dev->mt76.phy.priv = &dev->phy;
+ INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
+ INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
++ INIT_DELAYED_WORK(&dev->phy.scan_work, mt7996_scan_work);
+ INIT_DELAYED_WORK(&dev->scs_work, mt7996_mcu_scs_sta_poll);
+ INIT_LIST_HEAD(&dev->sta_rc_list);
+ INIT_LIST_HEAD(&dev->twt_list);
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 8c44442..4e9dd2c 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2693,3 +2693,144 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
+ dev->twt.table_mask &= ~BIT(flow->table_id);
+ dev->twt.n_agrt--;
+ }
++
++static void
++mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
++ const u8 *dst)
++{
++ struct ieee80211_hw *hw = phy->mt76->hw;
++ struct cfg80211_scan_request *req = phy->scan_req;
++ struct ieee80211_vif *vif = phy->scan_vif;
++ struct mt7996_vif *mvif;
++ struct mt76_wcid *wcid;
++ struct ieee80211_tx_info *info;
++ struct sk_buff *skb;
++
++ if (!req || !vif)
++ return;
++
++ mvif = (struct mt7996_vif *)vif->drv_priv;
++ wcid = &mvif->sta.wcid;
++
++ skb = ieee80211_probereq_get(hw, vif->addr,
++ ssid->ssid, ssid->ssid_len, req->ie_len);
++ if (!skb)
++ return;
++
++ if (is_unicast_ether_addr(dst)) {
++ struct ieee80211_hdr_3addr *hdr =
++ (struct ieee80211_hdr_3addr *)skb->data;
++ memcpy(hdr->addr1, dst, ETH_ALEN);
++ memcpy(hdr->addr3, dst, ETH_ALEN);
++ }
++
++ info = IEEE80211_SKB_CB(skb);
++ if (req->no_cck)
++ info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
++
++ if (req->ie_len)
++ skb_put_data(skb, req->ie, req->ie_len);
++
++ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
++
++ rcu_read_lock();
++ if (!ieee80211_tx_prepare_skb(hw, vif, skb,
++ phy->scan_chan->band,
++ NULL)) {
++ rcu_read_unlock();
++ ieee80211_free_txskb(hw, skb);
++ return;
++ }
++
++ local_bh_disable();
++ mt76_tx(phy->mt76, NULL, wcid, skb);
++ local_bh_enable();
++
++ rcu_read_unlock();
++}
++
++void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted)
++{
++ struct cfg80211_scan_info info = {
++ .aborted = aborted,
++ };
++
++ ieee80211_scan_completed(phy->mt76->hw, &info);
++ phy->scan_chan = NULL;
++ phy->scan_req = NULL;
++ phy->scan_vif = NULL;
++ clear_bit(MT76_SCANNING, &phy->mt76->state);
++}
++
++static void mt7996_scan_check_sta(void *data, struct ieee80211_sta *sta)
++{
++ bool *has_sta = data;
++
++ if (*has_sta)
++ return;
++ *has_sta = true;
++}
++
++void mt7996_scan_work(struct work_struct *work)
++{
++ struct mt7996_phy *phy = container_of(work, struct mt7996_phy, scan_work.work);
++ struct ieee80211_hw *hw = phy->mt76->hw;
++ struct cfg80211_scan_request *req = phy->scan_req;
++ struct cfg80211_chan_def chandef = {};
++ int duration;
++ bool has_sta = false, active_scan = false;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ if (phy->scan_chan_idx >= req->n_channels) {
++ mt7996_scan_complete(phy, false);
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ mt7996_set_channel(phy, &hw->conf.chandef);
++
++ return;
++ }
++
++ ieee80211_iterate_stations_atomic(hw, mt7996_scan_check_sta, &has_sta);
++
++ /* go back to operating channel */
++ if (has_sta && phy->scan_chan) {
++ phy->scan_chan = NULL;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ mt7996_set_channel(phy, &phy->mt76->chandef);
++
++ ieee80211_queue_delayed_work(hw, &phy->scan_work, HZ / 10);
++
++ return;
++ }
++
++ wiphy_info(hw->wiphy, "hw scan %d MHz\n",
++ req->channels[phy->scan_chan_idx]->center_freq);
++
++ phy->scan_chan = req->channels[phy->scan_chan_idx++];
++
++ if (!req->n_ssids ||
++ (phy->scan_chan->flags & (IEEE80211_CHAN_NO_IR |
++ IEEE80211_CHAN_RADAR))) {
++ duration = HZ / 9; /* ~110 ms */
++ } else {
++ duration = HZ / 16; /* ~60 ms */
++ active_scan = true;
++ }
++
++ cfg80211_chandef_create(&chandef, phy->scan_chan, NL80211_CHAN_HT20);
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ mt7996_set_channel(phy, &chandef);
++
++ if (active_scan) {
++ int i;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ for (i = 0; i < req->n_ssids; i++)
++ mt7996_scan_send_probe(phy, &req->ssids[i], req->bssid);
++ mutex_unlock(&phy->dev->mt76.mutex);
++ }
++
++ ieee80211_queue_delayed_work(hw, &phy->scan_work, duration);
++}
+diff --git a/mt7996/main.c b/mt7996/main.c
+index c9e8108..5c1735e 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -312,6 +312,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ int idx = msta->wcid.idx;
+
++ cancel_delayed_work_sync(&phy->scan_work);
++
+ mt7996_mcu_add_sta(dev, vif, NULL, false, false);
+ mt7996_mcu_add_bss_info(phy, vif, false);
+
+@@ -323,6 +325,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+
+ mutex_lock(&dev->mt76.mutex);
++
++ if (test_bit(MT76_SCANNING, &phy->mt76->state))
++ mt7996_scan_complete(phy, true);
++
+ dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
+ phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
+ mutex_unlock(&dev->mt76.mutex);
+@@ -335,7 +341,33 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ mt76_wcid_cleanup(&dev->mt76, &msta->wcid);
+ }
+
+-int mt7996_set_channel(struct mt7996_phy *phy)
++static void ___mt7996_set_channel(struct mt7996_phy *phy,
++ struct cfg80211_chan_def *chandef)
++{
++ struct mt76_dev *mdev = phy->mt76->dev;
++ struct mt76_phy *mphy = phy->mt76;
++ bool offchannel = phy->scan_chan != NULL;
++ int timeout = HZ / 5;
++
++ wait_event_timeout(mdev->tx_wait, !mt76_has_tx_pending(mphy), timeout);
++ mt76_update_survey(mphy);
++
++ if (mphy->chandef.chan->center_freq != chandef->chan->center_freq ||
++ mphy->chandef.width != chandef->width)
++ mphy->dfs_state = MT_DFS_STATE_UNKNOWN;
++
++ mphy->chandef = *chandef;
++ mphy->chan_state = mt76_channel_state(mphy, chandef->chan);
++
++ if (!offchannel)
++ mphy->main_chan = chandef->chan;
++
++ if (chandef->chan != mphy->main_chan)
++ memset(mphy->chan_state, 0, sizeof(*mphy->chan_state));
++}
++
++static int __mt7996_set_channel(struct mt7996_phy *phy,
++ struct cfg80211_chan_def *chandef)
+ {
+ struct mt7996_dev *dev = phy->dev;
+ int ret;
+@@ -345,7 +377,7 @@ int mt7996_set_channel(struct mt7996_phy *phy)
+ mutex_lock(&dev->mt76.mutex);
+ set_bit(MT76_RESET, &phy->mt76->state);
+
+- mt76_set_channel(phy->mt76);
++ ___mt7996_set_channel(phy, chandef);
+
+ if (dev->cal) {
+ ret = mt7996_mcu_apply_tx_dpd(phy);
+@@ -381,6 +413,19 @@ out:
+ return ret;
+ }
+
++int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef)
++{
++ int ret;
++
++ ieee80211_stop_queues(phy->mt76->hw);
++ ret = __mt7996_set_channel(phy, chandef);
++ if (ret)
++ return ret;
++ ieee80211_wake_queues(phy->mt76->hw);
++
++ return 0;
++}
++
+ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+@@ -477,11 +522,7 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+ if (ret)
+ return ret;
+
+- ieee80211_stop_queues(hw);
+- ret = mt7996_set_channel(phy);
+- if (ret)
+- return ret;
+- ieee80211_wake_queues(hw);
++ mt7996_set_channel(phy, &hw->conf.chandef);
+ }
+
+ if (changed & (IEEE80211_CONF_CHANGE_POWER |
+@@ -1648,6 +1689,42 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+
+ #endif
+
++static int
++mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_scan_request *hw_req)
++{
++ struct cfg80211_scan_request *req = &hw_req->req;
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ if (WARN_ON(phy->scan_req || phy->scan_chan)) {
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return -EBUSY;
++ }
++
++ set_bit(MT76_SCANNING, &phy->mt76->state);
++ phy->scan_req = req;
++ phy->scan_vif = vif;
++ phy->scan_chan_idx = 0;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ ieee80211_queue_delayed_work(hw, &phy->scan_work, 0);
++
++ return 0;
++}
++
++static void
++mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
++{
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++
++ cancel_delayed_work_sync(&phy->scan_work);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ mt7996_scan_complete(phy, true);
++ mutex_unlock(&phy->dev->mt76.mutex);
++}
++
+ const struct ieee80211_ops mt7996_ops = {
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+@@ -1666,8 +1743,8 @@ const struct ieee80211_ops mt7996_ops = {
+ .ampdu_action = mt7996_ampdu_action,
+ .set_rts_threshold = mt7996_set_rts_threshold,
+ .wake_tx_queue = mt76_wake_tx_queue,
+- .sw_scan_start = mt76_sw_scan,
+- .sw_scan_complete = mt76_sw_scan_complete,
++ .hw_scan = mt7996_hw_scan,
++ .cancel_hw_scan = mt7996_cancel_hw_scan,
+ .release_buffered_frames = mt76_release_buffered_frames,
+ .get_txpower = mt76_get_txpower,
+ .channel_switch_beacon = mt7996_channel_switch_beacon,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index e38a507..9f2d125 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3775,7 +3775,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
+ if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
+ req.switch_reason = CH_SWITCH_NORMAL;
+ else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
+- phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
++ phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE ||
++ phy->scan_chan)
+ req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
+ else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
+ NL80211_IFTYPE_AP))
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index d03d3d9..fbf1e83 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -458,6 +458,13 @@ struct mt7996_phy {
+ u8 pp_mode;
+ u16 punct_bitmap;
+
++ /* for hw_scan */
++ struct delayed_work scan_work;
++ struct ieee80211_channel *scan_chan;
++ struct cfg80211_scan_request *scan_req;
++ struct ieee80211_vif *scan_vif;
++ int scan_chan_idx;
++
+ struct mt7996_scs_ctrl scs_ctrl;
+ u32 red_drop;
+
+@@ -806,7 +813,7 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_he_obss_pd *he_obss_pd);
+ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool changed);
+-int mt7996_set_channel(struct mt7996_phy *phy);
++int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
+ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
+ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif);
+ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+@@ -964,6 +971,8 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb, u32 *info);
+ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
+ void mt7996_stats_work(struct work_struct *work);
++void mt7996_scan_work(struct work_struct *work);
++void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted);
+ int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
+ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);
+ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy);
+--
+2.18.0
+