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

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
...@@ -276,6 +276,7 @@ enum { ...@@ -276,6 +276,7 @@ enum {
MT76_STATE_MCU_RUNNING, MT76_STATE_MCU_RUNNING,
MT76_SCANNING, MT76_SCANNING,
MT76_HW_SCANNING, MT76_HW_SCANNING,
MT76_HW_SCHED_SCANNING,
MT76_RESTART, MT76_RESTART,
MT76_RESET, MT76_RESET,
MT76_MCU_RESET, MT76_MCU_RESET,
......
...@@ -349,7 +349,12 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) ...@@ -349,7 +349,12 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
wiphy->reg_notifier = mt7615_regd_notifier; 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_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->max_scan_ssids = 4;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
...@@ -409,6 +414,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) ...@@ -409,6 +414,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
return 0; return 0;
INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work);
skb_queue_head_init(&phy->scan_event_list);
mt7615_cap_dbdc_enable(dev); mt7615_cap_dbdc_enable(dev);
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops);
...@@ -467,6 +473,7 @@ void mt7615_init_device(struct mt7615_dev *dev) ...@@ -467,6 +473,7 @@ void mt7615_init_device(struct mt7615_dev *dev)
dev->mt76.phy.priv = &dev->phy; dev->mt76.phy.priv = &dev->phy;
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_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); INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock); spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait); init_waitqueue_head(&dev->reset_wait);
......
...@@ -170,7 +170,8 @@ static void ...@@ -170,7 +170,8 @@ static void
mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy,
struct mt76_rx_status *status, u8 chfreq) 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->freq = mphy->chandef.chan->center_freq;
status->band = mphy->chandef.chan->band; status->band = mphy->chandef.chan->band;
return; return;
......
...@@ -705,16 +705,36 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ...@@ -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) void mt7615_scan_work(struct work_struct *work)
{ {
struct cfg80211_scan_info info = {
.aborted = false,
};
struct mt7615_phy *phy; struct mt7615_phy *phy;
phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
scan_work.work); 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); clear_bit(MT76_HW_SCANNING, &phy->mt76->state);
ieee80211_scan_completed(phy->mt76->hw, &info); 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 static int
...@@ -734,6 +754,29 @@ mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ...@@ -734,6 +754,29 @@ mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mt7615_mcu_cancel_hw_scan(mphy->priv, 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 = { const struct ieee80211_ops mt7615_ops = {
.tx = mt7615_tx, .tx = mt7615_tx,
.start = mt7615_start, .start = mt7615_start,
...@@ -765,6 +808,8 @@ const struct ieee80211_ops mt7615_ops = { ...@@ -765,6 +808,8 @@ const struct ieee80211_ops mt7615_ops = {
.set_coverage_class = mt7615_set_coverage_class, .set_coverage_class = mt7615_set_coverage_class,
.hw_scan = mt7615_hw_scan, .hw_scan = mt7615_hw_scan,
.cancel_hw_scan = mt7615_cancel_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) static int __init mt7615_init(void)
......
...@@ -318,21 +318,23 @@ mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) ...@@ -318,21 +318,23 @@ mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
} }
static void 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; u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd);
struct mt7615_hw_scan_done *event;
struct mt7615_phy *phy; struct mt7615_phy *phy;
struct mt76_phy *mphy; struct mt76_phy *mphy;
skb_pull(skb, sizeof(*rxd)); if (*seq_num & BIT(7) && dev->mt76.phy2)
event = (struct mt7615_hw_scan_done *)skb->data;
if (event->seq_num & BIT(7) && dev->mt76.phy2)
mphy = dev->mt76.phy2; mphy = dev->mt76.phy2;
else else
mphy = &dev->mt76.phy; mphy = &dev->mt76.phy;
phy = (struct mt7615_phy *)mphy->priv; 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, ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
MT7615_HW_SCAN_TIMEOUT); MT7615_HW_SCAN_TIMEOUT);
} }
...@@ -346,9 +348,10 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) ...@@ -346,9 +348,10 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
case MCU_EVENT_EXT: case MCU_EVENT_EXT:
mt7615_mcu_rx_ext_event(dev, skb); mt7615_mcu_rx_ext_event(dev, skb);
break; break;
case MCU_EVENT_SCHED_SCAN_DONE:
case MCU_EVENT_SCAN_DONE: case MCU_EVENT_SCAN_DONE:
mt7615_mcu_scan_done_event(dev, skb); mt7615_mcu_scan_event(dev, skb);
break; return;
default: default:
break; break;
} }
...@@ -363,6 +366,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) ...@@ -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_FW_LOG_2_HOST ||
rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
rxd->eid == MCU_EVENT_SCAN_DONE || rxd->eid == MCU_EVENT_SCAN_DONE ||
!rxd->seq) !rxd->seq)
mt7615_mcu_rx_unsolicited_event(dev, skb); mt7615_mcu_rx_unsolicited_event(dev, skb);
...@@ -2614,3 +2618,93 @@ int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, ...@@ -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, return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req,
sizeof(req), false); 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);
}
...@@ -83,6 +83,7 @@ enum { ...@@ -83,6 +83,7 @@ enum {
MCU_EVENT_MT_PATCH_SEM = 0x04, MCU_EVENT_MT_PATCH_SEM = 0x04,
MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_SCAN_DONE = 0x0d,
MCU_EVENT_CH_PRIVILEGE = 0x18, MCU_EVENT_CH_PRIVILEGE = 0x18,
MCU_EVENT_SCHED_SCAN_DONE = 0x23,
MCU_EVENT_EXT = 0xed, MCU_EVENT_EXT = 0xed,
MCU_EVENT_RESTART_DL = 0xef, MCU_EVENT_RESTART_DL = 0xef,
}; };
...@@ -291,6 +292,13 @@ struct mt7615_mcu_scan_channel { ...@@ -291,6 +292,13 @@ struct mt7615_mcu_scan_channel {
u8 channel_num; u8 channel_num;
} __packed; } __packed;
struct mt7615_mcu_scan_match {
__le32 rssi_th;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
u8 rsv[3];
} __packed;
struct mt7615_hw_scan_req { struct mt7615_hw_scan_req {
u8 seq_num; u8 seq_num;
u8 bss_idx; u8 bss_idx;
...@@ -365,11 +373,38 @@ struct mt7615_hw_scan_done { ...@@ -365,11 +373,38 @@ struct mt7615_hw_scan_done {
__le32 beacon_5g_num; __le32 beacon_5g_num;
} __packed; } __packed;
struct mt7615_sched_scan_req {
u8 version;
u8 seq_num;
u8 stop_on_match;
u8 ssids_num;
u8 match_num;
u8 pad;
__le16 ie_len;
struct mt7615_mcu_scan_ssid ssids[MT7615_MAX_SCHED_SCAN_SSID];
struct mt7615_mcu_scan_match match[MT7615_MAX_SCAN_MATCH];
u8 channel_type;
u8 channels_num;
u8 intervals_num;
u8 scan_func;
struct mt7615_mcu_scan_channel channels[64];
__le16 intervals[MT7615_MAX_SCHED_SCAN_INTERVAL];
u8 pad2[64];
} __packed;
struct nt7615_sched_scan_done {
u8 seq_num;
u8 status; /* 0: ssid found */
__le16 pad;
} __packed;
/* offload mcu commands */ /* offload mcu commands */
enum { enum {
MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03,
MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f,
MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b,
MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61,
MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62,
}; };
#define MCU_CMD_ACK BIT(0) #define MCU_CMD_ACK BIT(0)
......
...@@ -59,6 +59,9 @@ ...@@ -59,6 +59,9 @@
#define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ #define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
#define MT7615_SCAN_IE_LEN 600 #define MT7615_SCAN_IE_LEN 600
#define MT7615_MAX_SCHED_SCAN_INTERVAL 10
#define MT7615_MAX_SCHED_SCAN_SSID 10
#define MT7615_MAX_SCAN_MATCH 16
struct mt7615_vif; struct mt7615_vif;
struct mt7615_sta; struct mt7615_sta;
...@@ -155,6 +158,7 @@ struct mt7615_phy { ...@@ -155,6 +158,7 @@ struct mt7615_phy {
struct mib_stats mib; struct mib_stats mib;
struct sk_buff_head scan_event_list;
struct delayed_work scan_work; struct delayed_work scan_work;
}; };
...@@ -412,6 +416,12 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, ...@@ -412,6 +416,12 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_scan_request *scan_req); struct ieee80211_scan_request *scan_req);
int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy,
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *sreq);
int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy,
struct ieee80211_vif *vif,
bool enable);
int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid, enum mt76_txq_id qid, struct mt76_wcid *wcid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment