2022-10-12 00:27:14

by Sean Wang

[permalink] [raw]
Subject: [PATCH v2 1/7] wifi: mt76: connac: add mt76_connac_mcu_uni_set_chctx

From: Sean Wang <[email protected]>

add mt76_connac_mcu_uni_set_chctx to set up the channel context per BSS
in the firmware

Signed-off-by: Sean Wang <[email protected]>
---
v2:
1. remove unneeded newline
2. squash this one with "wifi: mt76: connac: rely on mt76_connac_mcu_uni_set_chctx"
---
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 147 ++++++++++--------
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 3 +
2 files changed, 82 insertions(+), 68 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 011fc9729b38..4b12d65dc076 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1313,44 +1313,13 @@ mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif,
he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
}

-int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
- struct ieee80211_vif *vif,
- struct mt76_wcid *wcid,
- bool enable)
+int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif,
+ struct ieee80211_chanctx_conf *ctx)
{
- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
- struct cfg80211_chan_def *chandef = &phy->chandef;
+ struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef;
int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
enum nl80211_band band = chandef->chan->band;
struct mt76_dev *mdev = phy->dev;
- struct {
- struct {
- u8 bss_idx;
- u8 pad[3];
- } __packed hdr;
- struct mt76_connac_bss_basic_tlv basic;
- struct mt76_connac_bss_qos_tlv qos;
- } basic_req = {
- .hdr = {
- .bss_idx = mvif->idx,
- },
- .basic = {
- .tag = cpu_to_le16(UNI_BSS_INFO_BASIC),
- .len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)),
- .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
- .dtim_period = vif->bss_conf.dtim_period,
- .omac_idx = mvif->omac_idx,
- .band_idx = mvif->band_idx,
- .wmm_idx = mvif->wmm_idx,
- .active = true, /* keep bss deactivated */
- .phymode = mt76_connac_get_phy_mode(phy, vif, band, NULL),
- },
- .qos = {
- .tag = cpu_to_le16(UNI_BSS_INFO_QBSS),
- .len = cpu_to_le16(sizeof(struct mt76_connac_bss_qos_tlv)),
- .qos = vif->bss_conf.qos,
- },
- };
struct {
struct {
u8 bss_idx;
@@ -1388,6 +1357,81 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
.band = band,
},
};
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_40:
+ rlm_req.rlm.bw = CMD_CBW_40MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ rlm_req.rlm.bw = CMD_CBW_80MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ rlm_req.rlm.bw = CMD_CBW_8080MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ rlm_req.rlm.bw = CMD_CBW_160MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_5:
+ rlm_req.rlm.bw = CMD_CBW_5MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_10:
+ rlm_req.rlm.bw = CMD_CBW_10MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ default:
+ rlm_req.rlm.bw = CMD_CBW_20MHZ;
+ rlm_req.rlm.ht_op_info = 0;
+ break;
+ }
+
+ if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan)
+ rlm_req.rlm.sco = 1; /* SCA */
+ else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan)
+ rlm_req.rlm.sco = 3; /* SCB */
+
+ return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &rlm_req,
+ sizeof(rlm_req), true);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_set_chctx);
+
+int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
+ struct ieee80211_vif *vif,
+ struct mt76_wcid *wcid,
+ bool enable)
+{
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct cfg80211_chan_def *chandef = &phy->chandef;
+ enum nl80211_band band = chandef->chan->band;
+ struct mt76_dev *mdev = phy->dev;
+ struct {
+ struct {
+ u8 bss_idx;
+ u8 pad[3];
+ } __packed hdr;
+ struct mt76_connac_bss_basic_tlv basic;
+ struct mt76_connac_bss_qos_tlv qos;
+ } basic_req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ },
+ .basic = {
+ .tag = cpu_to_le16(UNI_BSS_INFO_BASIC),
+ .len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)),
+ .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
+ .dtim_period = vif->bss_conf.dtim_period,
+ .omac_idx = mvif->omac_idx,
+ .band_idx = mvif->band_idx,
+ .wmm_idx = mvif->wmm_idx,
+ .active = true, /* keep bss deactivated */
+ .phymode = mt76_connac_get_phy_mode(phy, vif, band, NULL),
+ },
+ .qos = {
+ .tag = cpu_to_le16(UNI_BSS_INFO_QBSS),
+ .len = cpu_to_le16(sizeof(struct mt76_connac_bss_qos_tlv)),
+ .qos = vif->bss_conf.qos,
+ },
+ };
int err, conn_type;
u8 idx, basic_phy;

@@ -1474,40 +1518,7 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
return err;
}

- switch (chandef->width) {
- case NL80211_CHAN_WIDTH_40:
- rlm_req.rlm.bw = CMD_CBW_40MHZ;
- break;
- case NL80211_CHAN_WIDTH_80:
- rlm_req.rlm.bw = CMD_CBW_80MHZ;
- break;
- case NL80211_CHAN_WIDTH_80P80:
- rlm_req.rlm.bw = CMD_CBW_8080MHZ;
- break;
- case NL80211_CHAN_WIDTH_160:
- rlm_req.rlm.bw = CMD_CBW_160MHZ;
- break;
- case NL80211_CHAN_WIDTH_5:
- rlm_req.rlm.bw = CMD_CBW_5MHZ;
- break;
- case NL80211_CHAN_WIDTH_10:
- rlm_req.rlm.bw = CMD_CBW_10MHZ;
- break;
- case NL80211_CHAN_WIDTH_20_NOHT:
- case NL80211_CHAN_WIDTH_20:
- default:
- rlm_req.rlm.bw = CMD_CBW_20MHZ;
- rlm_req.rlm.ht_op_info = 0;
- break;
- }
-
- if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan)
- rlm_req.rlm.sco = 1; /* SCA */
- else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan)
- rlm_req.rlm.sco = 3; /* SCB */
-
- return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &rlm_req,
- sizeof(rlm_req), true);
+ return mt76_connac_mcu_uni_set_chctx(phy, mvif, NULL);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index cf4ce3b1fc21..b7e29b177a6c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1736,6 +1736,9 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,
int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
struct ieee80211_ampdu_params *params,
int cmd, bool enable, bool tx);
+int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy,
+ struct mt76_vif *vif,
+ struct ieee80211_chanctx_conf *ctx);
int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
--
2.25.1


2022-10-12 00:27:52

by Sean Wang

[permalink] [raw]
Subject: [PATCH v2 6/7] wifi: mt76: mt7921: introduce remain_on_channel support

From: Sean Wang <[email protected]>

Introduce remain_on_channel support. Additionally, we add
mt7921_check_offload_capability to disable .remain_on_channel and
.cancel_remain_on_channel and related configuration because those
operations would rely on the fundamental MCU commands that will be only
supported with newer firmware.

Co-developed-by: Deren Wu <[email protected]>
Signed-off-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
v2: move mt7921_check_offload_capability prior to ieee80211_alloc_hw
and decie what ieee80211_ops instance we should use by the
firmware capability bit.
---
.../net/wireless/mediatek/mt76/mt7921/init.c | 63 +++++++
.../net/wireless/mediatek/mt76/mt7921/main.c | 165 ++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 24 +++
.../wireless/mediatek/mt76/mt7921/mt7921.h | 49 ++++++
.../net/wireless/mediatek/mt76/mt7921/pci.c | 26 ++-
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 17 +-
.../net/wireless/mediatek/mt76/mt7921/usb.c | 17 +-
7 files changed, 347 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index dcdb3cf04ac1..482b601f86d9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2020 MediaTek Inc. */

#include <linux/etherdevice.h>
+#include <linux/firmware.h>
#include "mt7921.h"
#include "mac.h"
#include "mcu.h"
@@ -65,12 +66,18 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
hw->sta_data_size = sizeof(struct mt7921_sta);
hw->vif_data_size = sizeof(struct mt7921_vif);

+ if (dev->fw_features & MT7921_FW_CAP_CNM)
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ else
+ wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
wiphy->iface_combinations = if_comb;
wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
WIPHY_FLAG_4ADDR_STATION);
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ wiphy->max_remain_on_channel_duration = 5000;
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_scan_ssids = 4;
wiphy->max_sched_scan_plan_interval =
@@ -129,6 +136,58 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
}

+u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
+{
+ const struct mt76_connac2_fw_trailer *hdr;
+ struct mt7921_realease_info *rel_info;
+ struct mt7921_fw_features *features;
+ const struct firmware *fw;
+ int ret, i, offset = 0;
+ const u8 *data, *end;
+
+ ret = request_firmware(&fw, fw_wm, dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+ dev_err(dev, "Invalid firmware\n");
+ return -EINVAL;
+ }
+
+ data = fw->data;
+ hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
+
+ for (i = 0; i < hdr->n_region; i++) {
+ const struct mt76_connac2_fw_region *region;
+
+ region = (const void *)((const u8 *)hdr -
+ (hdr->n_region - i) * sizeof(*region));
+ offset += le32_to_cpu(region->len);
+ }
+
+ data += offset + 16;
+ rel_info = (struct mt7921_realease_info *)data;
+ data += sizeof(*rel_info);
+ end = data + le16_to_cpu(rel_info->len);
+
+ while (data < end) {
+ rel_info = (struct mt7921_realease_info *)data;
+ data += sizeof(*rel_info);
+
+ if (rel_info->tag == MT7921_FW_TAG_FEATURE) {
+ features = (struct mt7921_fw_features *)data;
+ break;
+ }
+
+ data += le16_to_cpu(rel_info->len) + rel_info->pad_len;
+ }
+
+ release_firmware(fw);
+
+ return features->data;
+}
+EXPORT_SYMBOL_GPL(mt7921_check_offload_capability);
+
int mt7921_mac_init(struct mt7921_dev *dev)
{
int i;
@@ -278,6 +337,10 @@ int mt7921_register_device(struct mt7921_dev *dev)
INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
INIT_WORK(&dev->init_work, mt7921_init_work);

+ INIT_WORK(&dev->phy.roc_work, mt7921_roc_work);
+ timer_setup(&dev->phy.roc_timer, mt7921_roc_timer, 0);
+ init_waitqueue_head(&dev->phy.roc_wait);
+
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 82df5fa4fbc7..8e9257d3cc54 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -386,6 +386,116 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
mt76_packet_id_flush(&dev->mt76, &msta->wcid);
}

+static void mt7921_roc_iter(void *priv, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_phy *phy = priv;
+
+ mt7921_mcu_abort_roc(phy, mvif, phy->roc_token_id);
+}
+
+void mt7921_roc_work(struct work_struct *work)
+{
+ struct mt7921_phy *phy;
+
+ phy = (struct mt7921_phy *)container_of(work, struct mt7921_phy,
+ roc_work);
+
+ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ return;
+
+ mt7921_mutex_acquire(phy->dev);
+ ieee80211_iterate_active_interfaces(phy->mt76->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7921_roc_iter, phy);
+ mt7921_mutex_release(phy->dev);
+ ieee80211_remain_on_channel_expired(phy->mt76->hw);
+}
+
+void mt7921_roc_timer(struct timer_list *timer)
+{
+ struct mt7921_phy *phy = from_timer(phy, timer, roc_timer);
+
+ ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
+}
+
+static int mt7921_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif)
+{
+ int err;
+
+ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ return 0;
+
+ del_timer_sync(&phy->roc_timer);
+ cancel_work_sync(&phy->roc_work);
+ err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
+ clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+
+ return 00;
+}
+
+static int mt7921_set_roc(struct mt7921_phy *phy,
+ struct mt7921_vif *vif,
+ struct ieee80211_channel *chan,
+ int duration,
+ enum mt7921_roc_req type)
+{
+ int err;
+
+ if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))
+ return -EBUSY;
+
+ phy->roc_grant = false;
+
+ err = mt7921_mcu_set_roc(phy, vif, chan, duration, type,
+ ++phy->roc_token_id);
+ if (err < 0) {
+ clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+ goto out;
+ }
+
+ if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) {
+ mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
+ clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+ err = -ETIMEDOUT;
+ }
+
+out:
+ return err;
+}
+
+static int mt7921_remain_on_channel(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel *chan,
+ int duration,
+ enum ieee80211_roc_type type)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ int err;
+
+ mt7921_mutex_acquire(phy->dev);
+ err = mt7921_set_roc(phy, mvif, chan, duration, MT7921_ROC_REQ_ROC);
+ mt7921_mutex_release(phy->dev);
+
+ return err;
+}
+
+static int mt7921_cancel_remain_on_channel(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ int err;
+
+ mt7921_mutex_acquire(phy->dev);
+ err = mt7921_abort_roc(phy, mvif);
+ mt7921_mutex_release(phy->dev);
+
+ return err;
+}
+
static int mt7921_set_channel(struct mt7921_phy *phy)
{
struct mt7921_dev *dev = phy->dev;
@@ -1573,6 +1683,61 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt7921_mutex_release(dev);
}

+const struct ieee80211_ops mt7921_ops_chanctx = {
+ .tx = mt7921_tx,
+ .start = mt7921_start,
+ .stop = mt7921_stop,
+ .add_interface = mt7921_add_interface,
+ .remove_interface = mt7921_remove_interface,
+ .config = mt7921_config,
+ .conf_tx = mt7921_conf_tx,
+ .configure_filter = mt7921_configure_filter,
+ .bss_info_changed = mt7921_bss_info_changed,
+ .start_ap = mt7921_start_ap,
+ .stop_ap = mt7921_stop_ap,
+ .sta_state = mt7921_sta_state,
+ .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
+ .set_key = mt7921_set_key,
+ .sta_set_decap_offload = mt7921_sta_set_decap_offload,
+#if IS_ENABLED(CONFIG_IPV6)
+ .ipv6_addr_change = mt7921_ipv6_addr_change,
+#endif /* CONFIG_IPV6 */
+ .ampdu_action = mt7921_ampdu_action,
+ .set_rts_threshold = mt7921_set_rts_threshold,
+ .wake_tx_queue = mt76_wake_tx_queue,
+ .release_buffered_frames = mt76_release_buffered_frames,
+ .channel_switch_beacon = mt7921_channel_switch_beacon,
+ .get_txpower = mt76_get_txpower,
+ .get_stats = mt7921_get_stats,
+ .get_et_sset_count = mt7921_get_et_sset_count,
+ .get_et_strings = mt7921_get_et_strings,
+ .get_et_stats = mt7921_get_et_stats,
+ .get_tsf = mt7921_get_tsf,
+ .set_tsf = mt7921_set_tsf,
+ .get_survey = mt76_get_survey,
+ .get_antenna = mt76_get_antenna,
+ .set_antenna = mt7921_set_antenna,
+ .set_coverage_class = mt7921_set_coverage_class,
+ .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,
+ CFG80211_TESTMODE_CMD(mt7921_testmode_cmd)
+ CFG80211_TESTMODE_DUMP(mt7921_testmode_dump)
+#ifdef CONFIG_PM
+ .suspend = mt7921_suspend,
+ .resume = mt7921_resume,
+ .set_wakeup = mt7921_set_wakeup,
+ .set_rekey_data = mt7921_set_rekey_data,
+#endif /* CONFIG_PM */
+ .flush = mt7921_flush,
+ .set_sar_specs = mt7921_set_sar_specs,
+ .remain_on_channel = mt7921_remain_on_channel,
+ .cancel_remain_on_channel = mt7921_cancel_remain_on_channel,
+};
+EXPORT_SYMBOL_GPL(mt7921_ops_chanctx);
+
const struct ieee80211_ops mt7921_ops = {
.tx = mt7921_tx,
.start = mt7921_start,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 7a74abecb269..fb9c0f66cb27 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -154,6 +154,29 @@ void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)

#endif /* CONFIG_PM */

+static void
+mt7921_mcu_uni_roc_event(struct mt7921_dev *dev, struct sk_buff *skb)
+{
+ struct mt7921_roc_grant_tlv *grant;
+ struct mt76_connac2_mcu_rxd *rxd;
+ int duration;
+
+ rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
+ grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4);
+
+ /* should never happen */
+ WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT));
+
+ if (grant->reqtype == MT7921_ROC_REQ_ROC)
+ ieee80211_ready_on_channel(dev->mt76.phy.hw);
+
+ dev->phy.roc_grant = true;
+ wake_up(&dev->phy.roc_wait);
+ duration = le32_to_cpu(grant->max_interval);
+ mod_timer(&dev->phy.roc_timer,
+ round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
+}
+
static void
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
@@ -295,6 +318,7 @@ mt7921_mcu_uni_rx_unsolicited_event(struct mt7921_dev *dev,

switch (rxd->eid) {
case MCU_UNI_EVENT_ROC:
+ mt7921_mcu_uni_roc_event(dev, skb);
break;
default:
break;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index d9d78f6b088e..ab1bf34d5616 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -32,6 +32,9 @@
#define MT7921_MCU_INIT_RETRY_COUNT 10
#define MT7921_WFSYS_INIT_RETRY_COUNT 2

+#define MT7921_FW_TAG_FEATURE 4
+#define MT7921_FW_CAP_CNM BIT(7)
+
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"

@@ -67,6 +70,41 @@ enum mt7921_roc_req {
MT7921_ROC_REQ_NUM
};

+enum {
+ UNI_EVENT_ROC_GRANT = 0,
+ UNI_EVENT_ROC_TAG_NUM
+};
+
+struct mt7921_realease_info {
+ __le16 len;
+ u8 pad_len;
+ u8 tag;
+} __packed;
+
+struct mt7921_fw_features {
+ u8 segment;
+ u8 data;
+ u8 rsv[14];
+} __packed;
+
+struct mt7921_roc_grant_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 bss_idx;
+ u8 tokenid;
+ u8 status;
+ u8 primarychannel;
+ u8 rfsco;
+ u8 rfband;
+ u8 channelwidth;
+ u8 centerfreqseg1;
+ u8 centerfreqseg2;
+ u8 reqtype;
+ u8 dbdcband;
+ u8 rsv[1];
+ __le32 max_interval;
+} __packed;
+
enum mt7921_sdio_pkt_type {
MT7921_SDIO_TXD,
MT7921_SDIO_DATA,
@@ -214,6 +252,12 @@ struct mt7921_phy {
#endif

struct mt7921_clc *clc[MT7921_CLC_MAX_NUM];
+
+ struct work_struct roc_work;
+ struct timer_list roc_timer;
+ wait_queue_head_t roc_wait;
+ u8 roc_token_id;
+ bool roc_grant;
};

#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
@@ -250,6 +294,7 @@ struct mt7921_dev {
struct work_struct init_work;

u8 fw_debug;
+ u8 fw_features;

struct mt76_connac_pm pm;
struct mt76_connac_coredump coredump;
@@ -312,6 +357,7 @@ mt7921_hw_dev(struct ieee80211_hw *hw)
mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm)

extern const struct ieee80211_ops mt7921_ops;
+extern const struct ieee80211_ops mt7921_ops_chanctx;

u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr);

@@ -439,6 +485,8 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable);
void mt7921_scan_work(struct work_struct *work);
+void mt7921_roc_work(struct work_struct *work);
+void mt7921_roc_timer(struct timer_list *timer);
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
@@ -527,4 +575,5 @@ int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
enum mt7921_roc_req type, u8 token_id);
int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
u8 token_id);
+u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index b38d119b2ea9..6e7ad52b3659 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -13,10 +13,14 @@
#include "../trace.h"

static const struct pci_device_id mt7921_pci_device_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961),
+ .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922),
+ .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608),
+ .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616),
+ .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
{ },
};

@@ -253,9 +257,11 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.fw_own = mt7921e_mcu_fw_pmctrl,
};

+ const struct ieee80211_ops *ops;
struct mt76_bus_ops *bus_ops;
struct mt7921_dev *dev;
struct mt76_dev *mdev;
+ u8 features;
int ret;

ret = pcim_enable_device(pdev);
@@ -279,8 +285,14 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (mt7921_disable_aspm)
mt76_pci_disable_aspm(pdev);

- mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7921_ops,
- &drv_ops);
+ features = mt7921_check_offload_capability(&pdev->dev, (const char *)
+ id->driver_data);
+ if (features & MT7921_FW_CAP_CNM)
+ ops = &mt7921_ops_chanctx;
+ else
+ ops = &mt7921_ops;
+
+ mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops);
if (!mdev) {
ret = -ENOMEM;
goto err_free_pci_vec;
@@ -289,8 +301,8 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mdev);

dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev->fw_features = features;
dev->hif_ops = &mt7921_pcie_ops;
-
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
index 377ca5fa3f6e..87c90eec0245 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -17,7 +17,8 @@
#include "mcu.h"

static const struct sdio_device_id mt7921s_table[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901),
+ .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
{ } /* Terminating entry */
};

@@ -122,18 +123,26 @@ static int mt7921s_probe(struct sdio_func *func,
.fw_own = mt7921s_mcu_fw_pmctrl,
};

+ const struct ieee80211_ops *ops;
struct mt7921_dev *dev;
struct mt76_dev *mdev;
+ u8 features;
int ret;

- mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops,
- &drv_ops);
+ features = mt7921_check_offload_capability(&func->dev, (const char *)
+ id->driver_data);
+ if (features & MT7921_FW_CAP_CNM)
+ ops = &mt7921_ops_chanctx;
+ else
+ ops = &mt7921_ops;
+
+ mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);
if (!mdev)
return -ENOMEM;

dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev->fw_features = features;
dev->hif_ops = &mt7921_sdio_ops;
-
sdio_set_drvdata(func, dev);

ret = mt76s_init(mdev, func, &mt7921s_ops);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index 89249f0b6aba..c83f2b8315a0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -13,7 +13,8 @@
#include "mac.h"

static const struct usb_device_id mt7921u_device_table[] = {
- { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
{ },
};

@@ -204,10 +205,18 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
struct ieee80211_hw *hw;
struct mt7921_dev *dev;
struct mt76_dev *mdev;
+ const void *ops_src;
+ u8 features;
int ret;

- ops = devm_kmemdup(&usb_intf->dev, &mt7921_ops, sizeof(mt7921_ops),
- GFP_KERNEL);
+ features = mt7921_check_offload_capability(&usb_intf->dev, (const char *)
+ id->driver_info);
+ if (features & MT7921_FW_CAP_CNM)
+ ops_src = &mt7921_ops_chanctx;
+ else
+ ops_src = &mt7921_ops;
+
+ ops = devm_kmemdup(&usb_intf->dev, ops_src, sizeof(*ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;

@@ -218,7 +227,9 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
return -ENOMEM;

dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev->fw_features = features;
dev->hif_ops = &hif_ops;
+ dev->ops = ops;

udev = usb_get_dev(udev);
usb_reset_device(udev);
--
2.25.1

2022-10-12 00:28:00

by Sean Wang

[permalink] [raw]
Subject: [PATCH v2 2/7] wifi: mt76: mt7921: add chanctx parameter to mt76_connac_mcu_uni_add_bss signature

From: Sean Wang <[email protected]>

Add a chanctx parameter to mt76_connac_mcu_uni_add_bss signature to allow
the firmware binds the BSS into the specific channel context.

Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 7 ++++---
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 3 ++-
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 10 ++++++----
5 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 3dac76e6df4d..83f30305414d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -1119,7 +1119,7 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;

return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
- enable);
+ enable, NULL);
}

static inline int
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 4b12d65dc076..fffdb6976e52 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1398,10 +1398,11 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_set_chctx);
int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
- bool enable)
+ bool enable,
+ struct ieee80211_chanctx_conf *ctx)
{
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
- struct cfg80211_chan_def *chandef = &phy->chandef;
+ struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef;
enum nl80211_band band = chandef->chan->band;
struct mt76_dev *mdev = phy->dev;
struct {
@@ -1518,7 +1519,7 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
return err;
}

- return mt76_connac_mcu_uni_set_chctx(phy, mvif, NULL);
+ return mt76_connac_mcu_uni_set_chctx(phy, mvif, ctx);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index b7e29b177a6c..bc1c47daa81a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1742,7 +1742,8 @@ int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy,
int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
- bool enable);
+ bool enable,
+ struct ieee80211_chanctx_conf *ctx);
int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
struct mt76_sta_cmd_info *info);
void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 6860468ed191..2cf709a80b5f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -866,7 +866,7 @@ mt7921_vif_connect_iter(void *priv, u8 *mac,

if (vif->type == NL80211_IFTYPE_AP) {
mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.wcid,
- true);
+ true, NULL);
mt7921_mcu_sta_update(dev, NULL, vif, true,
MT76_STA_INFO_STATE_NONE);
mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, true);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 7e409ac7d9a8..82df5fa4fbc7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -748,7 +748,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,

if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
- true);
+ true, NULL);

mt7921_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -780,7 +780,8 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
ewma_rssi_init(&mvif->rssi);
if (!sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif,
- &mvif->sta.wcid, false);
+ &mvif->sta.wcid, false,
+ NULL);
}

spin_lock_bh(&dev->sta_poll_lock);
@@ -1534,7 +1535,7 @@ mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt7921_mutex_acquire(dev);

err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
- true);
+ true, NULL);
if (err)
goto out;

@@ -1565,7 +1566,8 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (err)
goto out;

- mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false);
+ mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false,
+ NULL);

out:
mt7921_mutex_release(dev);
--
2.25.1

2022-10-12 00:29:06

by Sean Wang

[permalink] [raw]
Subject: [PATCH v2 4/7] wifi: mt76: mt7921: drop ieee80211_[start, stop]_queues in driver

From: Sean Wang <[email protected]>

The firmware would be in charge of braking and continuing the traffic while
the channel contexts are switching between different BSS and HW SCAN in the
background.

Signed-off-by: Sean Wang <[email protected]>
---
v2: drop mt7921_mcu_bss_event that is unused any more
---
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 18 ------------------
1 file changed, 18 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 2b36c5f6eb40..7a74abecb269 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -199,20 +199,6 @@ mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
mt7921_mcu_connection_loss_iter, event);
}

-static void
-mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_connac_mcu_bss_event *event;
-
- skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
- event = (struct mt76_connac_mcu_bss_event *)skb->data;
- if (event->is_absent)
- ieee80211_stop_queues(mphy->hw);
- else
- ieee80211_wake_queues(mphy->hw);
-}
-
static void
mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
@@ -279,9 +265,6 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
case MCU_EVENT_SCAN_DONE:
mt7921_mcu_scan_event(dev, skb);
return;
- case MCU_EVENT_BSS_ABSENCE:
- mt7921_mcu_bss_event(dev, skb);
- break;
case MCU_EVENT_DBG_MSG:
mt7921_mcu_debug_msg_event(dev, skb);
break;
@@ -341,7 +324,6 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT ||
rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
- rxd->eid == MCU_EVENT_BSS_ABSENCE ||
rxd->eid == MCU_EVENT_SCAN_DONE ||
rxd->eid == MCU_EVENT_TX_DONE ||
rxd->eid == MCU_EVENT_DBG_MSG ||
--
2.25.1

2022-10-12 00:30:17

by Sean Wang

[permalink] [raw]
Subject: [PATCH v2 7/7] wifi: mt76: mt7921: introduce chanctx support

From: Sean Wang <[email protected]>

The firmware can have the capability to manage the channel context
scheduling on multiple roles running on the device including Station,
AP and P2P GC/GO mode (will be extended based on the patchset) to help
users sharing the network with others on a single device.

The firmware is able to support the channel chanctx up to 2 interface
simultaneously running on the different channels.

Another thing to be noted is that before the driver is going sent out the
management frames, the driver has to get the privilege from the firmware
to occupy the current channel context until the frame handshake is
completed and then get the privilege back to the firmware.

We temporarily disable the feature with a module parameter
mt7921_disable_cnm for a while until we can ensure the patchset doesn't
cause any regression.

Co-developed-by: Deren Wu <[email protected]>
Signed-off-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
v2:
1. decide the feature by the firmware capability bit
2. decide the channel by the hardware value in mt7921_get_status_freq_info()
---
.../net/wireless/mediatek/mt76/mt7921/init.c | 33 +++++-
.../net/wireless/mediatek/mt76/mt7921/mac.c | 8 --
.../net/wireless/mediatek/mt76/mt7921/main.c | 111 +++++++++++++++++-
.../wireless/mediatek/mt76/mt7921/mt7921.h | 1 +
4 files changed, 136 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 482b601f86d9..cc6cb7301bd9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -26,6 +26,27 @@ static const struct ieee80211_iface_combination if_comb[] = {
.max_interfaces = MT7921_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
+ },
+};
+
+static const struct ieee80211_iface_limit if_limits_chanctx[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP),
+ }
+};
+
+static const struct ieee80211_iface_combination if_comb_chanctx[] = {
+ {
+ .limits = if_limits_chanctx,
+ .n_limits = ARRAY_SIZE(if_limits_chanctx),
+ .max_interfaces = 2,
+ .num_different_channels = 2,
+ .beacon_int_infra_match = false,
}
};

@@ -66,17 +87,19 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
hw->sta_data_size = sizeof(struct mt7921_sta);
hw->vif_data_size = sizeof(struct mt7921_vif);

- if (dev->fw_features & MT7921_FW_CAP_CNM)
+ if (dev->fw_features & MT7921_FW_CAP_CNM) {
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- else
+ wiphy->iface_combinations = if_comb_chanctx;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx);
+ } else {
wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-
- wiphy->iface_combinations = if_comb;
+ wiphy->iface_combinations = if_comb;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ }
wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
WIPHY_FLAG_4ADDR_STATION);
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
- wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
wiphy->max_remain_on_channel_duration = 5000;
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_scan_ssids = 4;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 2cf709a80b5f..08c9a2cec687 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -168,14 +168,6 @@ static void
mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy,
struct mt76_rx_status *status, u8 chfreq)
{
- if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
- !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) &&
- !test_bit(MT76_STATE_ROC, &mphy->state)) {
- status->freq = mphy->chandef.chan->center_freq;
- status->band = mphy->chandef.chan->band;
- return;
- }
-
if (chfreq > 180) {
status->band = NL80211_BAND_6GHZ;
chfreq = (chfreq - 181) * 4 + 1;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 8e9257d3cc54..6e400a5a5e4e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -858,7 +858,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,

if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
- true, NULL);
+ true, mvif->ctx);

mt7921_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -891,7 +891,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (!sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif,
&mvif->sta.wcid, false,
- NULL);
+ mvif->ctx);
}

spin_lock_bh(&dev->sta_poll_lock);
@@ -1645,7 +1645,7 @@ mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt7921_mutex_acquire(dev);

err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
- true, NULL);
+ true, mvif->ctx);
if (err)
goto out;

@@ -1677,12 +1677,108 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;

mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false,
- NULL);
+ mvif->ctx);

out:
mt7921_mutex_release(dev);
}

+static int
+mt7921_add_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ return 0;
+}
+
+static void
+mt7921_remove_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+}
+
+static void mt7921_ctx_iter(void *priv, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct ieee80211_chanctx_conf *ctx = priv;
+
+ if (ctx != mvif->ctx)
+ return;
+
+ mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx);
+}
+
+static void
+mt7921_change_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx,
+ u32 changed)
+{
+ struct mt7921_phy *phy = mt7921_hw_phy(hw);
+
+ mt7921_mutex_acquire(phy->dev);
+ ieee80211_iterate_active_interfaces(phy->mt76->hw,
+ IEEE80211_IFACE_ITER_ACTIVE,
+ mt7921_ctx_iter, ctx);
+ mt7921_mutex_release(phy->dev);
+}
+
+static int
+mt7921_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+ mvif->ctx = ctx;
+ mutex_unlock(&dev->mt76.mutex);
+
+ return 0;
+}
+
+static void
+mt7921_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+ mvif->ctx = NULL;
+ mutex_unlock(&dev->mt76.mutex);
+}
+
+static void mt7921_mgd_prepare_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_prep_tx_info *info)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ u16 duration = info->duration ? info->duration :
+ jiffies_to_msecs(HZ);
+
+ mt7921_mutex_acquire(dev);
+ mt7921_set_roc(mvif->phy, mvif, mvif->ctx->def.chan, duration,
+ MT7921_ROC_REQ_JOIN);
+ mt7921_mutex_release(dev);
+}
+
+static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_prep_tx_info *info)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+ mt7921_mutex_acquire(dev);
+ mt7921_abort_roc(mvif->phy, mvif);
+ mt7921_mutex_release(dev);
+}
+
const struct ieee80211_ops mt7921_ops_chanctx = {
.tx = mt7921_tx,
.start = mt7921_start,
@@ -1735,6 +1831,13 @@ const struct ieee80211_ops mt7921_ops_chanctx = {
.set_sar_specs = mt7921_set_sar_specs,
.remain_on_channel = mt7921_remain_on_channel,
.cancel_remain_on_channel = mt7921_cancel_remain_on_channel,
+ .add_chanctx = mt7921_add_chanctx,
+ .remove_chanctx = mt7921_remove_chanctx,
+ .change_chanctx = mt7921_change_chanctx,
+ .assign_vif_chanctx = mt7921_assign_vif_chanctx,
+ .unassign_vif_chanctx = mt7921_unassign_vif_chanctx,
+ .mgd_prepare_tx = mt7921_mgd_prepare_tx,
+ .mgd_complete_tx = mt7921_mgd_complete_tx,
};
EXPORT_SYMBOL_GPL(mt7921_ops_chanctx);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index ab1bf34d5616..681356c80870 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -171,6 +171,7 @@ struct mt7921_vif {
struct ewma_rssi rssi;

struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+ struct ieee80211_chanctx_conf *ctx;
};

struct mib_stats {
--
2.25.1

2022-10-12 05:52:42

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 1/7] wifi: mt76: connac: add mt76_connac_mcu_uni_set_chctx

<[email protected]> writes:

> From: Sean Wang <[email protected]>
>
> add mt76_connac_mcu_uni_set_chctx to set up the channel context per BSS
> in the firmware
>
> Signed-off-by: Sean Wang <[email protected]>

BTW a cover letter, with an overview what the patchset does, would be
nice. But no need to resend because of this.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2022-10-12 05:58:52

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] wifi: mt76: mt7921: introduce remain_on_channel support

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on wireless-next/main]
[also build test WARNING on wireless/main linus/master next-20221012]
[cannot apply to v6.0]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/sean-wang-mediatek-com/wifi-mt76-connac-add-mt76_connac_mcu_uni_set_chctx/20221012-081836
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
config: loongarch-allyesconfig
compiler: loongarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/6a229606eb180ff1a7ddde8fd9f08861b48dd6b9
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review sean-wang-mediatek-com/wifi-mt76-connac-add-mt76_connac_mcu_uni_set_chctx/20221012-081836
git checkout 6a229606eb180ff1a7ddde8fd9f08861b48dd6b9
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch SHELL=/bin/bash drivers/net/wireless/mediatek/mt76/mt7921/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

drivers/net/wireless/mediatek/mt76/mt7921/main.c: In function 'mt7921_abort_roc':
>> drivers/net/wireless/mediatek/mt76/mt7921/main.c:425:13: warning: variable 'err' set but not used [-Wunused-but-set-variable]
425 | int err;
| ^~~


vim +/err +425 drivers/net/wireless/mediatek/mt76/mt7921/main.c

422
423 static int mt7921_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif)
424 {
> 425 int err;
426
427 if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
428 return 0;
429
430 del_timer_sync(&phy->roc_timer);
431 cancel_work_sync(&phy->roc_work);
432 err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
433 clear_bit(MT76_STATE_ROC, &phy->mt76->state);
434
435 return 00;
436 }
437

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (2.51 kB)
config (329.41 kB)
Download all attachments

2022-10-13 13:55:10

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] wifi: mt76: mt7921: introduce remain_on_channel support

Hi,

I love your patch! Yet something to improve:

[auto build test ERROR on wireless-next/main]
[also build test ERROR on wireless/main linus/master next-20221013]
[cannot apply to v6.0]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/sean-wang-mediatek-com/wifi-mt76-connac-add-mt76_connac_mcu_uni_set_chctx/20221012-081836
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
config: parisc-allmodconfig
compiler: hppa-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/6a229606eb180ff1a7ddde8fd9f08861b48dd6b9
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review sean-wang-mediatek-com/wifi-mt76-connac-add-mt76_connac_mcu_uni_set_chctx/20221012-081836
git checkout 6a229606eb180ff1a7ddde8fd9f08861b48dd6b9
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=parisc SHELL=/bin/bash drivers/net/wireless/mediatek/mt76/mt7921/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All error/warnings (new ones prefixed by >>):

drivers/net/wireless/mediatek/mt76/mt7921/main.c: In function 'mt7921_abort_roc':
>> drivers/net/wireless/mediatek/mt76/mt7921/main.c:425:13: warning: variable 'err' set but not used [-Wunused-but-set-variable]
425 | int err;
| ^~~
--
drivers/net/wireless/mediatek/mt76/mt7921/usb.c: In function 'mt7921u_probe':
>> drivers/net/wireless/mediatek/mt76/mt7921/usb.c:231:12: error: 'struct mt7921_dev' has no member named 'ops'
231 | dev->ops = ops;
| ^~


vim +231 drivers/net/wireless/mediatek/mt76/mt7921/usb.c

168
169 static int mt7921u_probe(struct usb_interface *usb_intf,
170 const struct usb_device_id *id)
171 {
172 static const struct mt76_driver_ops drv_ops = {
173 .txwi_size = MT_SDIO_TXD_SIZE,
174 .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ,
175 .survey_flags = SURVEY_INFO_TIME_TX |
176 SURVEY_INFO_TIME_RX |
177 SURVEY_INFO_TIME_BSS_RX,
178 .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb,
179 .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb,
180 .tx_status_data = mt7921_usb_sdio_tx_status_data,
181 .rx_skb = mt7921_queue_rx_skb,
182 .rx_check = mt7921_rx_check,
183 .sta_ps = mt7921_sta_ps,
184 .sta_add = mt7921_mac_sta_add,
185 .sta_assoc = mt7921_mac_sta_assoc,
186 .sta_remove = mt7921_mac_sta_remove,
187 .update_survey = mt7921_update_channel,
188 };
189 static const struct mt7921_hif_ops hif_ops = {
190 .mcu_init = mt7921u_mcu_init,
191 .init_reset = mt7921u_init_reset,
192 .reset = mt7921u_mac_reset,
193 };
194 static struct mt76_bus_ops bus_ops = {
195 .rr = mt7921u_rr,
196 .wr = mt7921u_wr,
197 .rmw = mt7921u_rmw,
198 .read_copy = mt76u_read_copy,
199 .write_copy = mt7921u_copy,
200 .type = MT76_BUS_USB,
201 };
202 struct usb_device *udev = interface_to_usbdev(usb_intf);
203 struct ieee80211_ops *ops;
204 struct ieee80211_hw *hw;
205 struct mt7921_dev *dev;
206 struct mt76_dev *mdev;
207 const void *ops_src;
208 u8 features;
209 int ret;
210
211 features = mt7921_check_offload_capability(&usb_intf->dev, (const char *)
212 id->driver_info);
213 if (features & MT7921_FW_CAP_CNM)
214 ops_src = &mt7921_ops_chanctx;
215 else
216 ops_src = &mt7921_ops;
217
218 ops = devm_kmemdup(&usb_intf->dev, ops_src, sizeof(*ops), GFP_KERNEL);
219 if (!ops)
220 return -ENOMEM;
221
222 ops->stop = mt7921u_stop;
223
224 mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);
225 if (!mdev)
226 return -ENOMEM;
227
228 dev = container_of(mdev, struct mt7921_dev, mt76);
229 dev->fw_features = features;
230 dev->hif_ops = &hif_ops;
> 231 dev->ops = ops;
232
233 udev = usb_get_dev(udev);
234 usb_reset_device(udev);
235
236 usb_set_intfdata(usb_intf, dev);
237
238 ret = __mt76u_init(mdev, usb_intf, &bus_ops);
239 if (ret < 0)
240 goto error;
241
242 mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
243 (mt76_rr(dev, MT_HW_REV) & 0xff);
244 dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
245
246 if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {
247 ret = mt7921u_wfsys_reset(dev);
248 if (ret)
249 goto error;
250 }
251
252 ret = mt7921u_mcu_power_on(dev);
253 if (ret)
254 goto error;
255
256 ret = mt76u_alloc_mcu_queue(&dev->mt76);
257 if (ret)
258 goto error;
259
260 ret = mt76u_alloc_queues(&dev->mt76);
261 if (ret)
262 goto error;
263
264 ret = mt7921u_dma_init(dev, false);
265 if (ret)
266 return ret;
267
268 hw = mt76_hw(dev);
269 /* check hw sg support in order to enable AMSDU */
270 hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;
271
272 ret = mt7921_register_device(dev);
273 if (ret)
274 goto error;
275
276 return 0;
277
278 error:
279 mt76u_queues_deinit(&dev->mt76);
280
281 usb_set_intfdata(usb_intf, NULL);
282 usb_put_dev(interface_to_usbdev(usb_intf));
283
284 mt76_free_device(&dev->mt76);
285
286 return ret;
287 }
288

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (6.08 kB)
config (312.54 kB)
Download all attachments

2022-10-13 13:55:13

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] wifi: mt76: mt7921: introduce remain_on_channel support

Hi,

I love your patch! Yet something to improve:

[auto build test ERROR on wireless-next/main]
[also build test ERROR on wireless/main linus/master next-20221012]
[cannot apply to v6.0]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/sean-wang-mediatek-com/wifi-mt76-connac-add-mt76_connac_mcu_uni_set_chctx/20221012-081836
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
config: powerpc-allmodconfig
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 791a7ae1ba3efd6bca96338e10ffde557ba83920)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install powerpc cross compiling tool for clang build
# apt-get install binutils-powerpc-linux-gnu
# https://github.com/intel-lab-lkp/linux/commit/6a229606eb180ff1a7ddde8fd9f08861b48dd6b9
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review sean-wang-mediatek-com/wifi-mt76-connac-add-mt76_connac_mcu_uni_set_chctx/20221012-081836
git checkout 6a229606eb180ff1a7ddde8fd9f08861b48dd6b9
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=powerpc SHELL=/bin/bash drivers/net/wireless/mediatek/mt76/mt7921/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All error/warnings (new ones prefixed by >>):

>> drivers/net/wireless/mediatek/mt76/mt7921/init.c:173:9: warning: variable 'features' is used uninitialized whenever 'while' loop exits because its condition is false [-Wsometimes-uninitialized]
while (data < end) {
^~~~~~~~~~
drivers/net/wireless/mediatek/mt76/mt7921/init.c:187:9: note: uninitialized use occurs here
return features->data;
^~~~~~~~
drivers/net/wireless/mediatek/mt76/mt7921/init.c:173:9: note: remove the condition if it is always true
while (data < end) {
^~~~~~~~~~
1
drivers/net/wireless/mediatek/mt76/mt7921/init.c:143:37: note: initialize the variable 'features' to silence this warning
struct mt7921_fw_features *features;
^
= NULL
1 warning generated.
--
>> drivers/net/wireless/mediatek/mt76/mt7921/usb.c:231:7: error: no member named 'ops' in 'struct mt7921_dev'
dev->ops = ops;
~~~ ^
1 error generated.


vim +231 drivers/net/wireless/mediatek/mt76/mt7921/usb.c

168
169 static int mt7921u_probe(struct usb_interface *usb_intf,
170 const struct usb_device_id *id)
171 {
172 static const struct mt76_driver_ops drv_ops = {
173 .txwi_size = MT_SDIO_TXD_SIZE,
174 .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ,
175 .survey_flags = SURVEY_INFO_TIME_TX |
176 SURVEY_INFO_TIME_RX |
177 SURVEY_INFO_TIME_BSS_RX,
178 .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb,
179 .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb,
180 .tx_status_data = mt7921_usb_sdio_tx_status_data,
181 .rx_skb = mt7921_queue_rx_skb,
182 .rx_check = mt7921_rx_check,
183 .sta_ps = mt7921_sta_ps,
184 .sta_add = mt7921_mac_sta_add,
185 .sta_assoc = mt7921_mac_sta_assoc,
186 .sta_remove = mt7921_mac_sta_remove,
187 .update_survey = mt7921_update_channel,
188 };
189 static const struct mt7921_hif_ops hif_ops = {
190 .mcu_init = mt7921u_mcu_init,
191 .init_reset = mt7921u_init_reset,
192 .reset = mt7921u_mac_reset,
193 };
194 static struct mt76_bus_ops bus_ops = {
195 .rr = mt7921u_rr,
196 .wr = mt7921u_wr,
197 .rmw = mt7921u_rmw,
198 .read_copy = mt76u_read_copy,
199 .write_copy = mt7921u_copy,
200 .type = MT76_BUS_USB,
201 };
202 struct usb_device *udev = interface_to_usbdev(usb_intf);
203 struct ieee80211_ops *ops;
204 struct ieee80211_hw *hw;
205 struct mt7921_dev *dev;
206 struct mt76_dev *mdev;
207 const void *ops_src;
208 u8 features;
209 int ret;
210
211 features = mt7921_check_offload_capability(&usb_intf->dev, (const char *)
212 id->driver_info);
213 if (features & MT7921_FW_CAP_CNM)
214 ops_src = &mt7921_ops_chanctx;
215 else
216 ops_src = &mt7921_ops;
217
218 ops = devm_kmemdup(&usb_intf->dev, ops_src, sizeof(*ops), GFP_KERNEL);
219 if (!ops)
220 return -ENOMEM;
221
222 ops->stop = mt7921u_stop;
223
224 mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);
225 if (!mdev)
226 return -ENOMEM;
227
228 dev = container_of(mdev, struct mt7921_dev, mt76);
229 dev->fw_features = features;
230 dev->hif_ops = &hif_ops;
> 231 dev->ops = ops;
232
233 udev = usb_get_dev(udev);
234 usb_reset_device(udev);
235
236 usb_set_intfdata(usb_intf, dev);
237
238 ret = __mt76u_init(mdev, usb_intf, &bus_ops);
239 if (ret < 0)
240 goto error;
241
242 mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
243 (mt76_rr(dev, MT_HW_REV) & 0xff);
244 dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
245
246 if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {
247 ret = mt7921u_wfsys_reset(dev);
248 if (ret)
249 goto error;
250 }
251
252 ret = mt7921u_mcu_power_on(dev);
253 if (ret)
254 goto error;
255
256 ret = mt76u_alloc_mcu_queue(&dev->mt76);
257 if (ret)
258 goto error;
259
260 ret = mt76u_alloc_queues(&dev->mt76);
261 if (ret)
262 goto error;
263
264 ret = mt7921u_dma_init(dev, false);
265 if (ret)
266 return ret;
267
268 hw = mt76_hw(dev);
269 /* check hw sg support in order to enable AMSDU */
270 hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;
271
272 ret = mt7921_register_device(dev);
273 if (ret)
274 goto error;
275
276 return 0;
277
278 error:
279 mt76u_queues_deinit(&dev->mt76);
280
281 usb_set_intfdata(usb_intf, NULL);
282 usb_put_dev(interface_to_usbdev(usb_intf));
283
284 mt76_free_device(&dev->mt76);
285
286 return ret;
287 }
288

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (6.81 kB)
config (325.57 kB)
Download all attachments