Commit 29f9d8b0 authored by Sean Wang's avatar Sean Wang Committed by Felix Fietkau
Browse files

mt76: mt7921: introduce schedule scan support



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: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Co-developed-by: default avatarSoul Huang <Soul.Huang@mediatek.com>
Signed-off-by: default avatarSoul Huang <Soul.Huang@mediatek.com>
Signed-off-by: default avatarSean Wang <sean.wang@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 474a9f21
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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);
+38 −0
Original line number Diff line number Diff line
@@ -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,
};
+83 −0
Original line number Diff line number Diff line
@@ -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 = {
+20 −0
Original line number Diff line number Diff line
@@ -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;
+9 −0
Original line number Diff line number Diff line
@@ -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);