]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mt76: mt7921: introduce schedule scan support
authorSean Wang <sean.wang@mediatek.com>
Wed, 27 Jan 2021 19:33:45 +0000 (03:33 +0800)
committerFelix Fietkau <nbd@nbd.name>
Fri, 29 Jan 2021 17:09:58 +0000 (18:09 +0100)
introduce schedule scan to control mt7921 firmware to do background scan in
defined plan to see if the matched SSID is available.

Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Co-developed-by: Soul Huang <Soul.Huang@mediatek.com>
Signed-off-by: Soul Huang <Soul.Huang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7921/init.c
drivers/net/wireless/mediatek/mt76/mt7921/main.c
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h

index 1ce87a4bfdd9a44a66b00cc563980b016bb77535..14d78370d525998557d008d987dbaa7f02586c38 100644 (file)
@@ -70,6 +70,11 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
        wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
        wiphy->max_scan_ie_len = MT7921_SCAN_IE_LEN;
        wiphy->max_scan_ssids = 4;
+       wiphy->max_sched_scan_plan_interval = MT7921_MAX_SCHED_SCAN_INTERVAL;
+       wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+       wiphy->max_sched_scan_ssids = MT7921_MAX_SCHED_SCAN_SSID;
+       wiphy->max_match_sets = MT7921_MAX_SCAN_MATCH;
+       wiphy->max_sched_scan_reqs = 1;
        wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
index ed82dc193bf3f4d476c28f1d0aab08de8243d1e1..018025a666a2f0cc08764874f07ef449c86e16d6 100644 (file)
@@ -868,6 +868,42 @@ mt7921_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        mutex_unlock(&dev->mt76.mutex);
 }
 
+static int
+mt7921_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       struct cfg80211_sched_scan_request *req,
+                       struct ieee80211_scan_ies *ies)
+{
+       struct mt7921_dev *dev = mt7921_hw_dev(hw);
+       struct mt76_phy *mphy = hw->priv;
+       int err;
+
+       mutex_lock(&dev->mt76.mutex);
+
+       err = mt7921_mcu_sched_scan_req(mphy->priv, vif, req);
+       if (err < 0)
+               goto out;
+
+       err = mt7921_mcu_sched_scan_enable(mphy->priv, vif, true);
+out:
+       mutex_unlock(&dev->mt76.mutex);
+
+       return err;
+}
+
+static int
+mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       struct mt7921_dev *dev = mt7921_hw_dev(hw);
+       struct mt76_phy *mphy = hw->priv;
+       int err;
+
+       mutex_lock(&dev->mt76.mutex);
+       err = mt7921_mcu_sched_scan_enable(mphy->priv, vif, false);
+       mutex_unlock(&dev->mt76.mutex);
+
+       return err;
+}
+
 static int
 mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 {
@@ -957,4 +993,6 @@ const struct ieee80211_ops mt7921_ops = {
        .hw_scan = mt7921_hw_scan,
        .cancel_hw_scan = mt7921_cancel_hw_scan,
        .sta_statistics = mt7921_sta_statistics,
+       .sched_scan_start = mt7921_start_sched_scan,
+       .sched_scan_stop = mt7921_stop_sched_scan,
 };
index ee4b525589745d1567eb1a385cf3445118ff2a51..6f2b4086ca81e7e363103d4acb36ad3c9f2f505b 100644 (file)
@@ -2361,6 +2361,89 @@ int mt7921_mcu_cancel_hw_scan(struct mt7921_phy *phy,
                                 sizeof(req), false);
 }
 
+int mt7921_mcu_sched_scan_req(struct mt7921_phy *phy,
+                             struct ieee80211_vif *vif,
+                             struct cfg80211_sched_scan_request *sreq)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct ieee80211_channel **scan_list = sreq->channels;
+       struct mt7921_dev *dev = phy->dev;
+       struct mt7921_mcu_scan_channel *chan;
+       struct mt7921_sched_scan_req *req;
+       struct cfg80211_match_set *match;
+       struct cfg80211_ssid *ssid;
+       struct sk_buff *skb;
+       int i;
+
+       skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
+                                sizeof(*req) + sreq->ie_len);
+       if (!skb)
+               return -ENOMEM;
+
+       mvif->mt76.scan_seq_num = (mvif->mt76.scan_seq_num + 1) & 0x7f;
+
+       req = (struct mt7921_sched_scan_req *)skb_put(skb, sizeof(*req));
+       req->version = 1;
+       req->seq_num = mvif->mt76.scan_seq_num;
+
+       req->ssids_num = sreq->n_ssids;
+       for (i = 0; i < req->ssids_num; i++) {
+               ssid = &sreq->ssids[i];
+               memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len);
+               req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len);
+       }
+
+       req->match_num = sreq->n_match_sets;
+       for (i = 0; i < req->match_num; i++) {
+               match = &sreq->match_sets[i];
+               memcpy(req->match[i].ssid, match->ssid.ssid,
+                      match->ssid.ssid_len);
+               req->match[i].rssi_th = cpu_to_le32(match->rssi_thold);
+               req->match[i].ssid_len = match->ssid.ssid_len;
+       }
+
+       req->channel_type = sreq->n_channels ? 4 : 0;
+       req->channels_num = min_t(u8, sreq->n_channels, 64);
+       for (i = 0; i < req->channels_num; i++) {
+               chan = &req->channels[i];
+               chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2;
+               chan->channel_num = scan_list[i]->hw_value;
+       }
+
+       req->intervals_num = sreq->n_scan_plans;
+       for (i = 0; i < req->intervals_num; i++)
+               req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval);
+
+       if (sreq->ie_len > 0) {
+               req->ie_len = cpu_to_le16(sreq->ie_len);
+               memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len);
+       }
+
+       return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SCHED_SCAN_REQ,
+                                    false);
+}
+
+int mt7921_mcu_sched_scan_enable(struct mt7921_phy *phy,
+                                struct ieee80211_vif *vif,
+                                bool enable)
+{
+       struct mt7921_dev *dev = phy->dev;
+       struct {
+               u8 active; /* 0: enabled 1: disabled */
+               u8 rsv[3];
+       } __packed req = {
+               .active = !enable,
+       };
+
+       if (enable)
+               set_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state);
+       else
+               clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state);
+
+       return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, &req,
+                                sizeof(req), false);
+}
+
 u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u16 wlan_idx)
 {
        struct mt7921_mcu_wlan_info wtbl_info = {
index 96eecea22d94024c4501b63c4252bc6e1ee26d9e..6894b44ff62d9b404726e8277d359e2c32ca1447 100644 (file)
@@ -879,6 +879,26 @@ struct mt7921_hw_scan_done {
        __le32 beacon_5g_num;
 } __packed;
 
+struct mt7921_sched_scan_req {
+       u8 version;
+       u8 seq_num;
+       u8 stop_on_match;
+       u8 ssids_num;
+       u8 match_num;
+       u8 pad;
+       __le16 ie_len;
+       struct mt7921_mcu_scan_ssid ssids[MT7921_MAX_SCHED_SCAN_SSID];
+       struct mt7921_mcu_scan_match match[MT7921_MAX_SCAN_MATCH];
+       u8 channel_type;
+       u8 channels_num;
+       u8 intervals_num;
+       u8 scan_func;
+       struct mt7921_mcu_scan_channel channels[64];
+       __le16 intervals[MT7921_MAX_SCHED_SCAN_INTERVAL];
+       u8 bss_idx;
+       u8 pad2[64];
+} __packed;
+
 struct mt7921_mcu_bss_event {
        u8 bss_idx;
        u8 is_absent;
index b08ece8544ff37d09ae01d37ca11f30691d39ff1..8cd9d3e214ed5680f7e77867d2bc83fb2b551a40 100644 (file)
@@ -44,6 +44,9 @@
 #define MT7921_SKU_TABLE_SIZE          (MT7921_SKU_RATE_NUM + 1)
 
 #define MT7921_SCAN_IE_LEN             600
+#define MT7921_MAX_SCHED_SCAN_INTERVAL 10
+#define MT7921_MAX_SCHED_SCAN_SSID     10
+#define MT7921_MAX_SCAN_MATCH          16
 
 struct mt7921_vif;
 struct mt7921_sta;
@@ -343,6 +346,12 @@ void mt7921_scan_work(struct work_struct *work);
 int mt7921_mcu_set_channel_domain(struct mt7921_phy *phy);
 int mt7921_mcu_hw_scan(struct mt7921_phy *phy, struct ieee80211_vif *vif,
                       struct ieee80211_scan_request *scan_req);
+int mt7921_mcu_sched_scan_req(struct mt7921_phy *phy,
+                             struct ieee80211_vif *vif,
+                             struct cfg80211_sched_scan_request *sreq);
+int mt7921_mcu_sched_scan_enable(struct mt7921_phy *phy,
+                                struct ieee80211_vif *vif,
+                                bool enable);
 int mt7921_mcu_cancel_hw_scan(struct mt7921_phy *phy,
                              struct ieee80211_vif *vif);
 u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u16 wlan_idx);