Commit 20305f98 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau
Browse files

mt76: mt7615: introduce scheduled scan support



Introduce scheduled scan support for mt7663e devices

Co-developed-by: default avatarSean Wang <sean.wang@mediatek.com>
Signed-off-by: default avatarSean Wang <sean.wang@mediatek.com>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent fcdfc29e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -276,6 +276,7 @@ enum {
	MT76_STATE_MCU_RUNNING,
	MT76_SCANNING,
	MT76_HW_SCANNING,
	MT76_HW_SCHED_SCANNING,
	MT76_RESTART,
	MT76_RESET,
	MT76_MCU_RESET,
+7 −0
Original line number Diff line number Diff line
@@ -349,7 +349,12 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
	wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
	wiphy->reg_notifier = mt7615_regd_notifier;

	wiphy->max_sched_scan_plan_interval = MT7615_MAX_SCHED_SCAN_INTERVAL;
	wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
	wiphy->max_scan_ie_len = MT7615_SCAN_IE_LEN;
	wiphy->max_sched_scan_ssids = MT7615_MAX_SCHED_SCAN_SSID;
	wiphy->max_match_sets = MT7615_MAX_SCAN_MATCH;
	wiphy->max_sched_scan_reqs = 1;
	wiphy->max_scan_ssids = 4;

	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
@@ -409,6 +414,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
		return 0;

	INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work);
	skb_queue_head_init(&phy->scan_event_list);

	mt7615_cap_dbdc_enable(dev);
	mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops);
@@ -467,6 +473,7 @@ void mt7615_init_device(struct mt7615_dev *dev)
	dev->mt76.phy.priv = &dev->phy;
	INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
	INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work);
	skb_queue_head_init(&dev->phy.scan_event_list);
	INIT_LIST_HEAD(&dev->sta_poll_list);
	spin_lock_init(&dev->sta_poll_lock);
	init_waitqueue_head(&dev->reset_wait);
+2 −1
Original line number Diff line number Diff line
@@ -170,7 +170,8 @@ static void
mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy,
			    struct mt76_rx_status *status, u8 chfreq)
{
	if (!test_bit(MT76_HW_SCANNING, &mphy->state)) {
	if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
	    !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) {
		status->freq = mphy->chandef.chan->center_freq;
		status->band = mphy->chandef.chan->band;
		return;
+50 −5
Original line number Diff line number Diff line
@@ -705,16 +705,36 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)

void mt7615_scan_work(struct work_struct *work)
{
	struct cfg80211_scan_info info = {
		.aborted = false,
	};
	struct mt7615_phy *phy;

	phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
						scan_work.work);

	while (true) {
		struct mt7615_mcu_rxd *rxd;
		struct sk_buff *skb;

		spin_lock_bh(&phy->dev->mt76.lock);
		skb = __skb_dequeue(&phy->scan_event_list);
		spin_unlock_bh(&phy->dev->mt76.lock);

		if (!skb)
			break;

		rxd = (struct mt7615_mcu_rxd *)skb->data;
		if (rxd->eid == MCU_EVENT_SCAN_DONE) {
			struct cfg80211_scan_info info = {
				.aborted = false,
			};

			clear_bit(MT76_HW_SCANNING, &phy->mt76->state);
			ieee80211_scan_completed(phy->mt76->hw, &info);
		} else {
			clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state);
			ieee80211_sched_scan_results(phy->mt76->hw);
		}
		dev_kfree_skb(skb);
	}
}

static int
@@ -734,6 +754,29 @@ mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
	mt7615_mcu_cancel_hw_scan(mphy->priv, vif);
}

static int
mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			struct cfg80211_sched_scan_request *req,
			struct ieee80211_scan_ies *ies)
{
	struct mt76_phy *mphy = hw->priv;
	int err;

	err = mt7615_mcu_sched_scan_req(mphy->priv, vif, req);
	if (err < 0)
		return err;

	return mt7615_mcu_sched_scan_enable(mphy->priv, vif, true);
}

static int
mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
	struct mt76_phy *mphy = hw->priv;

	return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false);
}

const struct ieee80211_ops mt7615_ops = {
	.tx = mt7615_tx,
	.start = mt7615_start,
@@ -765,6 +808,8 @@ const struct ieee80211_ops mt7615_ops = {
	.set_coverage_class = mt7615_set_coverage_class,
	.hw_scan = mt7615_hw_scan,
	.cancel_hw_scan = mt7615_cancel_hw_scan,
	.sched_scan_start = mt7615_start_sched_scan,
	.sched_scan_stop = mt7615_stop_sched_scan,
};

static int __init mt7615_init(void)
+102 −8
Original line number Diff line number Diff line
@@ -318,21 +318,23 @@ mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
}

static void
mt7615_mcu_scan_done_event(struct mt7615_dev *dev, struct sk_buff *skb)
mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
{
	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
	struct mt7615_hw_scan_done *event;
	u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd);
	struct mt7615_phy *phy;
	struct mt76_phy *mphy;

	skb_pull(skb, sizeof(*rxd));
	event = (struct mt7615_hw_scan_done *)skb->data;
	if (event->seq_num & BIT(7) && dev->mt76.phy2)
	if (*seq_num & BIT(7) && dev->mt76.phy2)
		mphy = dev->mt76.phy2;
	else
		mphy = &dev->mt76.phy;

	phy = (struct mt7615_phy *)mphy->priv;

	spin_lock_bh(&dev->mt76.lock);
	__skb_queue_tail(&phy->scan_event_list, skb);
	spin_unlock_bh(&dev->mt76.lock);

	ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
				     MT7615_HW_SCAN_TIMEOUT);
}
@@ -346,9 +348,10 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
	case MCU_EVENT_EXT:
		mt7615_mcu_rx_ext_event(dev, skb);
		break;
	case MCU_EVENT_SCHED_SCAN_DONE:
	case MCU_EVENT_SCAN_DONE:
		mt7615_mcu_scan_done_event(dev, skb);
		break;
		mt7615_mcu_scan_event(dev, skb);
		return;
	default:
		break;
	}
@@ -363,6 +366,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
	    rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
	    rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
	    rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
	    rxd->eid == MCU_EVENT_SCAN_DONE ||
	    !rxd->seq)
		mt7615_mcu_rx_unsolicited_event(dev, skb);
@@ -2614,3 +2618,93 @@ int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy,
	return __mt76_mcu_send_msg(&dev->mt76,  MCU_CMD_CANCEL_HW_SCAN, &req,
				   sizeof(req), false);
}

int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy,
			      struct ieee80211_vif *vif,
			      struct cfg80211_sched_scan_request *sreq)
{
	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
	struct ieee80211_channel **scan_list = sreq->channels;
	struct mt7615_dev *dev = phy->dev;
	bool ext_phy = phy != &dev->phy;
	struct mt7615_mcu_scan_channel *chan;
	struct mt7615_sched_scan_req *req;
	struct cfg80211_match_set *match;
	struct cfg80211_ssid *ssid;
	struct sk_buff *skb;
	int i;

	if (!mt7615_firmware_offload(dev))
		return -ENOTSUPP;

	skb = mt7615_mcu_msg_alloc(NULL, sizeof(*req) + sreq->ie_len);
	if (!skb)
		return -ENOMEM;

	mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;

	req = (struct mt7615_sched_scan_req *)skb_put(skb, sizeof(*req));
	req->version = 1;
	req->seq_num = mvif->scan_seq_num | ext_phy << 7;
	req->scan_func = !!(sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR);

	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 = 4;
	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 mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy,
				 struct ieee80211_vif *vif,
				 bool enable)
{
	struct mt7615_dev *dev = phy->dev;
	struct {
		u8 active; /* 0: enabled 1: disabled */
		u8 rsv[3];
	} __packed req = {
		.active = !enable,
	};

	if (!mt7615_firmware_offload(dev))
		return -ENOTSUPP;

	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);
}
Loading