From a8f424c1287cc79a06c21816658feea87dfcb83f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:34:56 +0100 Subject: [PATCH 01/16] wifi: mt76: add multi-radio remain_on_channel functions This allows a driver using the generic channel context functions to temporarily switch to another channel for off-channel rx/tx. Link: https://patch.msgid.link/20250102163508.52945-12-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/channel.c | 96 +++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mac80211.c | 3 + drivers/net/wireless/mediatek/mt76/mt76.h | 12 +++ drivers/net/wireless/mediatek/mt76/scan.c | 2 +- 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index ddb36e958c33..6a35c6ebd823 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -308,3 +308,99 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink); kfree(mlink); } + +static void mt76_roc_complete(struct mt76_phy *phy) +{ + struct mt76_vif_link *mlink = phy->roc_link; + + if (!phy->roc_vif) + return; + + if (mlink) + mlink->mvif->roc_phy = NULL; + if (phy->main_chandef.chan) + mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); + phy->roc_vif = NULL; + phy->roc_link = NULL; + ieee80211_remain_on_channel_expired(phy->hw); +} + +void mt76_roc_complete_work(struct work_struct *work) +{ + struct mt76_phy *phy = container_of(work, struct mt76_phy, roc_work.work); + struct mt76_dev *dev = phy->dev; + + mutex_lock(&dev->mutex); + mt76_roc_complete(phy); + mutex_unlock(&dev->mutex); +} + +void mt76_abort_roc(struct mt76_phy *phy) +{ + struct mt76_dev *dev = phy->dev; + + cancel_delayed_work_sync(&phy->roc_work); + + mutex_lock(&dev->mutex); + mt76_roc_complete(phy); + mutex_unlock(&dev->mutex); +} + +int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type) +{ + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_vif_link *mlink; + int ret = 0; + + phy = dev->band_phys[chan->band]; + if (!phy) + return -EINVAL; + + mutex_lock(&dev->mutex); + + if (phy->roc_vif || dev->scan.phy == phy) { + ret = -EBUSY; + goto out; + } + + mlink = mt76_get_vif_phy_link(phy, vif); + if (IS_ERR(mlink)) { + ret = PTR_ERR(mlink); + goto out; + } + + mlink->mvif->roc_phy = phy; + phy->roc_vif = vif; + phy->roc_link = mlink; + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); + mt76_set_channel(phy, &chandef, true); + ieee80211_ready_on_channel(hw); + ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, + msecs_to_jiffies(duration)); + +out: + mutex_unlock(&dev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(mt76_remain_on_channel); + +int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + struct mt76_phy *phy = mvif->roc_phy; + + if (!phy) + return 0; + + mt76_abort_roc(phy); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_cancel_remain_on_channel); diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 590c60f30823..508b472408c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -431,6 +431,7 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) INIT_LIST_HEAD(&phy->tx_list); spin_lock_init(&phy->tx_lock); + INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work); if ((void *)phy != hw->priv) return 0; @@ -1999,5 +2000,7 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif) rcu_assign_pointer(mvif->link[0], NULL); mt76_abort_scan(dev); + if (mvif->roc_phy) + mt76_abort_roc(mvif->roc_phy); } EXPORT_SYMBOL_GPL(mt76_vif_cleanup); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b61f1eb138e8..132148f7b107 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -787,6 +787,7 @@ struct mt76_vif_link { struct mt76_vif_data { struct mt76_vif_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct mt76_phy *roc_phy; u16 valid_links; u8 deflink_id; }; @@ -809,6 +810,10 @@ struct mt76_phy { bool offchannel; bool radar_enabled; + struct delayed_work roc_work; + struct ieee80211_vif *roc_vif; + struct mt76_vif_link *roc_link; + struct mt76_chanctx *chanctx; struct mt76_channel_state *chan_state; @@ -1521,6 +1526,11 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, enum ieee80211_chanctx_switch_mode mode); +int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type); +int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -1572,6 +1582,8 @@ int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, bool offchannel); void mt76_scan_work(struct work_struct *work); void mt76_abort_scan(struct mt76_dev *dev); +void mt76_roc_complete_work(struct work_struct *work); +void mt76_abort_roc(struct mt76_phy *phy); struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif); void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c index 9f3485be5747..1c4f9deaaada 100644 --- a/drivers/net/wireless/mediatek/mt76/scan.c +++ b/drivers/net/wireless/mediatek/mt76/scan.c @@ -134,7 +134,7 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mutex); - if (dev->scan.req) { + if (dev->scan.req || phy->roc_vif) { ret = -EBUSY; goto out; } -- 2.51.0 From c56d6edebc1f59afec7a59117ab50abd89879006 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:34:57 +0100 Subject: [PATCH 02/16] wifi: mt76: mt7996: use emulated hardware scan support Preparation for supporting multiple radios on a single wiphy Link: https://patch.msgid.link/20250102163508.52945-13-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7996/main.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 260cd1c34c64..400950aab9a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -439,6 +439,9 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; + + wiphy->max_scan_ssids = 4; + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 9f1460eca4f4..d7e33e3b04ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1522,8 +1522,8 @@ const struct ieee80211_ops mt7996_ops = { .ampdu_action = mt7996_ampdu_action, .set_rts_threshold = mt7996_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, - .sw_scan_start = mt76_sw_scan, - .sw_scan_complete = mt76_sw_scan_complete, + .hw_scan = mt76_hw_scan, + .cancel_hw_scan = mt76_cancel_hw_scan, .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7996_channel_switch_beacon, -- 2.51.0 From 0b57e944cee3d49eab33a8cf9e95b0862a90f441 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:34:58 +0100 Subject: [PATCH 03/16] wifi: mt76: mt7996: pass wcid to mt7996_mcu_sta_hdr_trans_tlv Preparation for MLO support. Link: https://patch.msgid.link/20250102163508.52945-14-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 1f0090c97e9c..ebb2ff15a8d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1795,11 +1795,9 @@ mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb) static void mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_vif *vif, struct mt76_wcid *wcid) { struct sta_rec_hdr_trans *hdr_trans; - struct mt76_wcid *wcid; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans)); @@ -1811,10 +1809,9 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb, else hdr_trans->from_ds = true; - if (!sta) + if (!wcid) return; - wcid = (struct mt76_wcid *)sta->drv_priv; hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { hdr_trans->to_ds = true; @@ -2194,7 +2191,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, goto out; /* starec hdr trans */ - mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta); + mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, &msta->wcid); /* starec tx proc */ mt7996_mcu_sta_tx_proc_tlv(skb); @@ -4322,7 +4319,7 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, return PTR_ERR(skb); /* starec hdr trans */ - mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta); + mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, &msta->wcid); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } -- 2.51.0 From 34a41bfbcb71f2fba26255c0552959efdcab742f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:34:59 +0100 Subject: [PATCH 04/16] wifi: mt76: mt7996: prepare mt7996_mcu_add_dev/bss_info for MLO support Add extra arguments for struct ieee80211_bss_conf and mt76_vif_link. Link: https://patch.msgid.link/20250102163508.52945-15-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/main.c | 38 +++-- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 146 ++++++++---------- .../wireless/mediatek/mt76/mt7996/mt7996.h | 11 +- 3 files changed, 99 insertions(+), 96 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index d7e33e3b04ac..6e90ecfecd8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -204,7 +204,7 @@ mt7996_vif_link_add(struct mt7996_phy *phy, struct ieee80211_vif *vif, mlink->mt76.wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; mlink->mt76.wcid = &mlink->sta.wcid; - ret = mt7996_mcu_add_dev_info(phy, vif, true); + ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, &mlink->mt76, true); if (ret) return ret; @@ -237,12 +237,13 @@ mt7996_vif_link_add(struct mt7996_phy *phy, struct ieee80211_vif *vif, mt7996_init_bitrate_mask(vif, mlink); - mt7996_mcu_add_bss_info(phy, vif, true); + mt7996_mcu_add_bss_info(phy, vif, link_conf, &mlink->mt76, true); /* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA * interface, since firmware only records BSSID when the entry is new */ if (vif->type != NL80211_IFTYPE_STATION) - mt7996_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, true); + mt7996_mcu_add_sta(dev, vif, &mlink->mt76, NULL, + CONN_STATE_PORT_SECURE, true); rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->sta.wcid); return 0; @@ -264,10 +265,11 @@ mt7996_vif_link_remove(struct mt7996_phy *phy, struct ieee80211_vif *vif, mlink->phy = NULL; msta = &mlink->sta; idx = msta->wcid.idx; - mt7996_mcu_add_sta(dev, vif, NULL, CONN_STATE_DISCONNECT, false); - mt7996_mcu_add_bss_info(phy, vif, false); + mt7996_mcu_add_sta(dev, vif, &mlink->mt76, NULL, CONN_STATE_DISCONNECT, + false); + mt7996_mcu_add_bss_info(phy, vif, link_conf, &mlink->mt76, false); - mt7996_mcu_add_dev_info(phy, vif, false); + mt7996_mcu_add_dev_info(phy, vif, link_conf, &mlink->mt76, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); @@ -397,7 +399,8 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == SET_KEY && !sta && !mlink->mt76.cipher) { mlink->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); - mt7996_mcu_add_bss_info(phy, vif, true); + mt7996_mcu_add_bss_info(phy, vif, &vif->bss_conf, &mlink->mt76, + true); } if (cmd == SET_KEY) { @@ -626,8 +629,8 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) || (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) || (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) { - mt7996_mcu_add_bss_info(phy, vif, true); - mt7996_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, + mt7996_mcu_add_bss_info(phy, vif, info, mvif, true); + mt7996_mcu_add_sta(dev, vif, mvif, NULL, CONN_STATE_PORT_SECURE, !!(changed & BSS_CHANGED_BSSID)); } @@ -697,7 +700,8 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - u8 band_idx = mvif->deflink.phy->mt76->band_idx; + struct mt7996_vif_link *link = &mvif->deflink; + u8 band_idx = link->phy->mt76->band_idx; int idx; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); @@ -715,7 +719,8 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, true); + mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, CONN_STATE_DISCONNECT, + true); return 0; } @@ -725,11 +730,14 @@ int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_vif_link *link = &mvif->deflink; int i, ret; switch (ev) { case MT76_STA_EVENT_ASSOC: - ret = mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_CONNECT, true); + ret = mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, + CONN_STATE_CONNECT, true); if (ret) return ret; @@ -743,13 +751,15 @@ int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, return 0; case MT76_STA_EVENT_AUTHORIZE: - return mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); + return mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, + CONN_STATE_PORT_SECURE, false); case MT76_STA_EVENT_DISASSOC: for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) mt7996_mac_twt_teardown_flow(dev, msta, i); - mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); + mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, + CONN_STATE_DISCONNECT, false); msta->wcid.sta_disabled = 1; msta->wcid.sta = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index ebb2ff15a8d8..43c728d39077 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -756,8 +756,7 @@ mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len) } static void -mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct mt7996_phy *phy) +mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { static const u8 rlm_ch_band[] = { [NL80211_BAND_2GHZ] = 1, @@ -787,8 +786,7 @@ mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } static void -mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct mt7996_phy *phy) +mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { struct bss_ra_tlv *ra; struct tlv *tlv; @@ -801,6 +799,7 @@ mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, static void mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct mt7996_phy *phy) { #define DEFAULT_HE_PE_DURATION 4 @@ -814,11 +813,11 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he)); he = (struct bss_info_uni_he *)tlv; - he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; + he->he_pe_duration = link_conf->htc_trig_based_pkt_ext; if (!he->he_pe_duration) he->he_pe_duration = DEFAULT_HE_PE_DURATION; - he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + he->he_rts_thres = cpu_to_le16(link_conf->frame_time_rts_th); if (!he->he_rts_thres) he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); @@ -828,13 +827,13 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } static void -mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct mt7996_phy *phy, int enable) +mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, + bool enable) { struct bss_info_uni_mbssid *mbssid; struct tlv *tlv; - if (!vif->bss_conf.bssid_indicator && enable) + if (!link_conf->bssid_indicator && enable) return; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_11V_MBSSID, sizeof(*mbssid)); @@ -842,23 +841,22 @@ mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, mbssid = (struct bss_info_uni_mbssid *)tlv; if (enable) { - mbssid->max_indicator = vif->bss_conf.bssid_indicator; - mbssid->mbss_idx = vif->bss_conf.bssid_index; + mbssid->max_indicator = link_conf->bssid_indicator; + mbssid->mbss_idx = link_conf->bssid_index; mbssid->tx_bss_omac_idx = 0; } } static void -mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, +mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink, struct mt7996_phy *phy) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct bss_rate_tlv *bmc; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; enum nl80211_band band = chandef->chan->band; struct tlv *tlv; - u8 idx = mvif->mcast_rates_idx ? - mvif->mcast_rates_idx : mvif->basic_rates_idx; + u8 idx = mlink->mcast_rates_idx ? + mlink->mcast_rates_idx : mlink->basic_rates_idx; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc)); @@ -882,9 +880,8 @@ mt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en) } static void -mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct bss_mld_tlv *mld; struct tlv *tlv; @@ -892,33 +889,28 @@ mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) mld = (struct bss_mld_tlv *)tlv; mld->group_mld_id = 0xff; - mld->own_mld_id = mvif->deflink.mt76.idx; + mld->own_mld_id = mlink->idx; mld->remap_idx = 0xff; } static void -mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct bss_sec_tlv *sec; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec)); sec = (struct bss_sec_tlv *)tlv; - sec->cipher = mvif->cipher; + sec->cipher = mlink->cipher; } static int -mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif, - bool bssid, bool enable) +mt7996_mcu_muar_config(struct mt7996_dev *dev, struct mt76_vif_link *mlink, + const u8 *addr, bool bssid, bool enable) { #define UNI_MUAR_ENTRY 2 - struct mt7996_dev *dev = phy->dev; - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - u32 idx = mvif->deflink.mt76.omac_idx - REPEATER_BSSID_START; - const u8 *addr = vif->addr; - + u32 idx = mlink->omac_idx - REPEATER_BSSID_START; struct { struct { u8 band; @@ -935,7 +927,7 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif, u8 addr[ETH_ALEN]; u8 __rsv[2]; } __packed req = { - .hdr.band = phy->mt76->band_idx, + .hdr.band = mlink->band_idx, .tag = cpu_to_le16(UNI_MUAR_ENTRY), .len = cpu_to_le16(sizeof(req) - sizeof(req.hdr)), .smesh = false, @@ -943,9 +935,6 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif, .entry_add = true, }; - if (bssid) - addr = vif->bss_conf.bssid; - if (enable) memcpy(req.addr, addr, ETH_ALEN); @@ -954,10 +943,8 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif, } static void -mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mvif->deflink.phy; struct bss_ifs_time_tlv *ifs_time; struct tlv *tlv; bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ; @@ -984,15 +971,16 @@ mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) static int mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mvif, struct mt76_phy *phy, u16 wlan_idx, bool enable) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct cfg80211_chan_def *chandef = &phy->chandef; struct mt76_connac_bss_basic_tlv *bss; u32 type = CONNECTION_INFRA_AP; u16 sta_wlan_idx = wlan_idx; + struct ieee80211_sta *sta; struct tlv *tlv; int idx; @@ -1004,9 +992,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, case NL80211_IFTYPE_STATION: if (enable) { rcu_read_lock(); - if (!sta) - sta = ieee80211_find_sta(vif, - vif->bss_conf.bssid); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ if (sta) { struct mt76_wcid *wcid; @@ -1029,8 +1015,8 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*bss)); bss = (struct mt76_connac_bss_basic_tlv *)tlv; - bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); - bss->dtim_period = vif->bss_conf.dtim_period; + bss->bcn_interval = cpu_to_le16(link_conf->beacon_int); + bss->dtim_period = link_conf->dtim_period; bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); bss->sta_idx = cpu_to_le16(sta_wlan_idx); bss->conn_type = cpu_to_le32(type); @@ -1048,8 +1034,8 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, return 0; } - memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); - bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + memcpy(bss->bssid, link_conf->bssid, ETH_ALEN); + bss->bcn_interval = cpu_to_le16(link_conf->beacon_int); bss->dtim_period = vif->bss_conf.dtim_period; bss->phymode = mt76_connac_get_phy_mode(phy, vif, chandef->chan->band, NULL); @@ -1076,46 +1062,46 @@ __mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, int return skb; } -int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, int enable) +int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, int enable) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = phy->dev; struct sk_buff *skb; - if (mvif->deflink.mt76.omac_idx >= REPEATER_BSSID_START) { - mt7996_mcu_muar_config(phy, vif, false, enable); - mt7996_mcu_muar_config(phy, vif, true, enable); + if (mlink->omac_idx >= REPEATER_BSSID_START) { + mt7996_mcu_muar_config(dev, mlink, link_conf->addr, false, enable); + mt7996_mcu_muar_config(dev, mlink, link_conf->bssid, true, enable); } - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); /* bss_basic must be first */ - mt7996_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76, - mvif->deflink.sta.wcid.idx, enable); - mt7996_mcu_bss_sec_tlv(skb, vif); + mt7996_mcu_bss_basic_tlv(skb, vif, link_conf, mlink, phy->mt76, + mlink->wcid->idx, enable); + mt7996_mcu_bss_sec_tlv(skb, mlink); if (vif->type == NL80211_IFTYPE_MONITOR) goto out; if (enable) { - mt7996_mcu_bss_rfch_tlv(skb, vif, phy); - mt7996_mcu_bss_bmc_tlv(skb, vif, phy); - mt7996_mcu_bss_ra_tlv(skb, vif, phy); + mt7996_mcu_bss_rfch_tlv(skb, phy); + mt7996_mcu_bss_bmc_tlv(skb, mlink, phy); + mt7996_mcu_bss_ra_tlv(skb, phy); mt7996_mcu_bss_txcmd_tlv(skb, true); - mt7996_mcu_bss_ifs_timing_tlv(skb, vif); + mt7996_mcu_bss_ifs_timing_tlv(skb, phy); if (vif->bss_conf.he_support) - mt7996_mcu_bss_he_tlv(skb, vif, phy); + mt7996_mcu_bss_he_tlv(skb, vif, link_conf, phy); /* this tag is necessary no matter if the vif is MLD */ - mt7996_mcu_bss_mld_tlv(skb, vif); + mt7996_mcu_bss_mld_tlv(skb, mlink); } - mt7996_mcu_bss_mbssid_tlv(skb, vif, phy, enable); + mt7996_mcu_bss_mbssid_tlv(skb, link_conf, enable); out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, @@ -1133,7 +1119,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) if (IS_ERR(skb)) return PTR_ERR(skb); - mt7996_mcu_bss_ifs_timing_tlv(skb, vif); + mt7996_mcu_bss_ifs_timing_tlv(skb, phy); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); @@ -2166,19 +2152,22 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif, } int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct mt76_vif_link *mlink, struct ieee80211_sta *sta, int conn_state, bool newly) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct ieee80211_link_sta *link_sta; - struct mt7996_sta *msta; + struct ieee80211_link_sta *link_sta = NULL; + struct mt76_wcid *wcid = mlink->wcid; struct sk_buff *skb; int ret; - msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->deflink.sta; - link_sta = sta ? &sta->deflink : NULL; + if (sta) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, - &msta->wcid, + wcid = &msta->wcid; + link_sta = &sta->deflink; + } + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -2191,7 +2180,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, goto out; /* starec hdr trans */ - mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, &msta->wcid); + mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, wcid); /* starec tx proc */ mt7996_mcu_sta_tx_proc_tlv(skb); @@ -2382,11 +2371,12 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } -int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, bool enable) + +int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, bool enable) { struct mt7996_dev *dev = phy->dev; - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct { struct req_hdr { u8 omac_idx; @@ -2402,8 +2392,8 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, } __packed tlv; } data = { .hdr = { - .omac_idx = mvif->deflink.mt76.omac_idx, - .band_idx = mvif->deflink.mt76.band_idx, + .omac_idx = mlink->omac_idx, + .band_idx = mlink->band_idx, }, .tlv = { .tag = cpu_to_le16(DEV_INFO_ACTIVE), @@ -2412,10 +2402,10 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, }, }; - if (mvif->deflink.mt76.omac_idx >= REPEATER_BSSID_START) - return mt7996_mcu_muar_config(phy, vif, false, enable); + if (mlink->omac_idx >= REPEATER_BSSID_START) + return mt7996_mcu_muar_config(dev, mlink, link_conf->addr, false, enable); - memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); + memcpy(data.tlv.omac_addr, link_conf->addr, ETH_ALEN); return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(DEV_INFO_UPDATE), &data, sizeof(data), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 31d1fdd61de6..006269d75e5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -516,11 +516,14 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev, struct mt7996_vif *mvif, struct mt7996_twt_flow *flow, int cmd); -int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, bool enable); -int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, int enable); +int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, bool enable); +int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, int enable); int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct mt76_vif_link *mlink, struct ieee80211_sta *sta, int conn_state, bool newly); int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, -- 2.51.0 From 747fe944506ff21118f627a8c05b475cc7a9f9fb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:00 +0100 Subject: [PATCH 05/16] wifi: mt76: mt7996: prepare mt7996_mcu_add_beacon for MLO support Pass in struct ieee80211_bss_conf. Link: https://patch.msgid.link/20250102163508.52945-16-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/main.c | 4 +- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 51 ++++++++++--------- .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 2656e3f85bdc..89523afa4aca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1593,7 +1593,7 @@ mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: - mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); + mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); break; default: break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 6e90ecfecd8f..ae4fad290785 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -669,7 +669,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, mvif->beacon_rates_idx = mt7996_get_rates_table(hw, vif, true, false); - mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); + mt7996_mcu_add_beacon(hw, vif, info); } if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | @@ -690,7 +690,7 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw, struct mt7996_dev *dev = mt7996_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mt7996_mcu_add_beacon(hw, vif, true); + mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); mutex_unlock(&dev->mt76.mutex); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 43c728d39077..a66ccc2512af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2411,9 +2411,9 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, } static void -mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, - struct sk_buff *skb, - struct ieee80211_mutable_offsets *offs) +mt7996_mcu_beacon_cntdwn(struct sk_buff *rskb, struct sk_buff *skb, + struct ieee80211_mutable_offsets *offs, + bool csa) { struct bss_bcn_cntdwn_tlv *info; struct tlv *tlv; @@ -2422,7 +2422,7 @@ mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, if (!offs->cntdwn_counter_offs[0]) return; - tag = vif->bss_conf.csa_active ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC; + tag = csa ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC; tlv = mt7996_mcu_add_uni_tlv(rskb, tag, sizeof(*info)); @@ -2432,16 +2432,13 @@ mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, static void mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, - struct ieee80211_vif *vif, struct bss_bcn_content_tlv *bcn, + struct bss_bcn_content_tlv *bcn, struct ieee80211_mutable_offsets *offs) { struct bss_bcn_mbss_tlv *mbss; const struct element *elem; struct tlv *tlv; - if (!vif->bss_conf.bssid_indicator) - return; - tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_MBSSID, sizeof(*mbss)); mbss = (struct bss_bcn_mbss_tlv *)tlv; @@ -2484,7 +2481,8 @@ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, } static void -mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif, +mt7996_mcu_beacon_cont(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, struct sk_buff *rskb, struct sk_buff *skb, struct bss_bcn_content_tlv *bcn, struct ieee80211_mutable_offsets *offs) @@ -2498,9 +2496,9 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif, if (offs->cntdwn_counter_offs[0]) { u16 offset = offs->cntdwn_counter_offs[0]; - if (vif->bss_conf.csa_active) + if (link_conf->csa_active) bcn->csa_ie_pos = cpu_to_le16(offset - 4); - if (vif->bss_conf.color_change_active) + if (link_conf->color_change_active) bcn->bcc_ie_pos = cpu_to_le16(offset - 3); } @@ -2511,12 +2509,11 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif, memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } -int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int en) +int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); struct ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; struct sk_buff *skb, *rskb; @@ -2524,15 +2521,18 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct bss_bcn_content_tlv *bcn; int len; - if (vif->bss_conf.nontransmitted) + if (link_conf->nontransmitted) return 0; - rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, + if (!mlink) + return -EINVAL; + + rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_MAX_BSS_OFFLOAD_SIZE); if (IS_ERR(rskb)) return PTR_ERR(rskb); - skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); + skb = ieee80211_beacon_get_template(hw, vif, &offs, link_conf->link_id); if (!skb) { dev_kfree_skb(rskb); return -EINVAL; @@ -2546,21 +2546,22 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, } info = IEEE80211_SKB_CB(skb); - info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mlink->band_idx); len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + skb->len, 4); tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len); bcn = (struct bss_bcn_content_tlv *)tlv; - bcn->enable = en; - if (!en) + bcn->enable = link_conf->enable_beacon; + if (!bcn->enable) goto out; - mt7996_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs); - mt7996_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs); - mt7996_mcu_beacon_cntdwn(vif, rskb, skb, &offs); + mt7996_mcu_beacon_cont(dev, link_conf, rskb, skb, bcn, &offs); + if (link_conf->bssid_indicator) + mt7996_mcu_beacon_mbss(rskb, skb, bcn, &offs); + mt7996_mcu_beacon_cntdwn(rskb, skb, &offs, link_conf->csa_active); out: dev_kfree_skb(skb); - return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, + return mt76_mcu_skb_send_msg(&dev->mt76, rskb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 006269d75e5e..7b12b1f8898b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -534,7 +534,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct cfg80211_he_bss_color *he_bss_color); int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - int enable); + struct ieee80211_bss_conf *link_conf); int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, struct ieee80211_vif *vif, u32 changed); int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif, -- 2.51.0 From c0df2f0caa8dde0d50f36649ee28a54c5079281b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:01 +0100 Subject: [PATCH 06/16] wifi: mt76: mt7996: prepare mt7996_mcu_set_tx for MLO support Pass in struct ieee80211_bss_conf in order to use link specific data. Link: https://patch.msgid.link/20250102163508.52945-17-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 9 +++++---- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index ae4fad290785..a1f1dee56dea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -469,7 +469,8 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_vif_link *mlink = mt7996_vif_link(dev, vif, link_id); static const u8 mq_to_aci[] = { [IEEE80211_AC_VO] = 3, [IEEE80211_AC_VI] = 2, @@ -478,7 +479,7 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, }; /* firmware uses access class index */ - mvif->deflink.queue_params[mq_to_aci[queue]] = *params; + mlink->queue_params[mq_to_aci[queue]] = *params; /* no need to update right away, we'll get BSS_CHANGED_QOS */ return 0; @@ -656,7 +657,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, /* ensure that enable txcmd_mode after bss_info */ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) - mt7996_mcu_set_tx(dev, vif); + mt7996_mcu_set_tx(dev, vif, info); if (changed & BSS_CHANGED_HE_OBSS_PD) mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index a66ccc2512af..e694edf4fa9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3145,7 +3145,8 @@ int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans) MCU_WM_UNI_CMD(RX_HDR_TRANS), true); } -int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif) +int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { #define MCU_EDCA_AC_PARAM 0 #define WMM_AIFS_SET BIT(0) @@ -3154,12 +3155,12 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif) #define WMM_TXOP_SET BIT(3) #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ WMM_CW_MAX_SET | WMM_TXOP_SET) - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); struct { u8 bss_idx; u8 __rsv[3]; } __packed hdr = { - .bss_idx = mvif->deflink.mt76.idx, + .bss_idx = link->mt76.idx, }; struct sk_buff *skb; int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca); @@ -3172,7 +3173,7 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif) skb_put_data(skb, &hdr, sizeof(hdr)); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &mvif->deflink.queue_params[ac]; + struct ieee80211_tx_queue_params *q = &link->queue_params[ac]; struct edca *e; struct tlv *tlv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 7b12b1f8898b..2b5c7cb7e817 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -543,7 +543,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool changed); int mt7996_set_channel(struct mt76_phy *mphy); int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag); -int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif); +int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version); int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, -- 2.51.0 From 97a1beb84c1c3a75db04279f7ceba882f94e25b4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:02 +0100 Subject: [PATCH 07/16] wifi: mt76: mt7996: prepare mt7996_mcu_set_timing for MLO support Pass in struct ieee80211_bss_conf in order to use link specific data. Link: https://patch.msgid.link/20250102163508.52945-18-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index a1f1dee56dea..95d915045cf7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -643,7 +643,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, if (slottime != phy->slottime) { phy->slottime = slottime; - mt7996_mcu_set_timing(phy, vif); + mt7996_mcu_set_timing(phy, vif, info); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index e694edf4fa9b..e9d449bd55ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1108,13 +1108,14 @@ out: MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } -int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) +int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = phy->dev; + struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); struct sk_buff *skb; - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 2b5c7cb7e817..604b67ea12e4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -562,7 +562,8 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index, const struct mt7996_dfs_pattern *pattern); int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); -int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif); +int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); int mt7996_mcu_get_temperature(struct mt7996_phy *phy); int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); -- 2.51.0 From 96fcecd9ba81a66b2b061cdcc10da1cc1b2a9b90 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:03 +0100 Subject: [PATCH 08/16] wifi: mt76: connac: prepare mt76_connac_mcu_sta_basic_tlv for MLO support Pass in struct ieee80211_bss_conf in order to use link specific data. Link: https://patch.msgid.link/20250102163508.52945-19-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 12 ++++++++---- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 5373937b0e04..b8fcd4eb3fbb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -865,8 +865,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, mvif->sta_added = true; } conn_state = enable ? CONN_STATE_PORT_SECURE : CONN_STATE_DISCONNECT; - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, link_sta, - conn_state, new_entry); + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, &vif->bss_conf, + link_sta, conn_state, new_entry); if (enable && sta) mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0, MT76_STA_INFO_STATE_ASSOC); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 5c76a0885278..6e52e184aa20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -369,10 +369,11 @@ void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb, EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv); void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta, int conn_state, bool newly) { + struct ieee80211_vif *vif = link_conf->vif; struct sta_rec_basic *basic; struct tlv *tlv; int conn_type; @@ -390,8 +391,8 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); if (vif->type == NL80211_IFTYPE_STATION && - !is_zero_ether_addr(vif->bss_conf.bssid)) { - memcpy(basic->peer_addr, vif->bss_conf.bssid, ETH_ALEN); + !is_zero_ether_addr(link_conf->bssid)) { + memcpy(basic->peer_addr, link_conf->bssid, ETH_ALEN); basic->aid = cpu_to_le16(vif->cfg.aid); } else { eth_broadcast_addr(basic->peer_addr); @@ -1049,6 +1050,9 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, struct sk_buff *skb; int conn_state; + if (!info->link_conf) + info->link_conf = &info->vif->bss_conf; + skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, info->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1057,7 +1061,7 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, CONN_STATE_DISCONNECT; link_sta = info->sta ? &info->sta->deflink : NULL; if (info->sta || !info->offload_fw) - mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, link_sta, conn_state, info->newly); if (info->sta && info->enable) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 8f23b9e58d2a..541b3c17168b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1758,6 +1758,7 @@ struct mt76_sta_cmd_info { struct mt76_wcid *wcid; struct ieee80211_vif *vif; + struct ieee80211_bss_conf *link_conf; bool offload_fw; bool enable; @@ -1903,7 +1904,7 @@ mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len) int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy); int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif); void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta, int state, bool newly); void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 7115394f6bd6..9d790f234e82 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1699,7 +1699,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, link_sta, + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf, link_sta, conn_state, newly); /* tag order is in accordance with firmware dependency. */ if (sta && conn_state != CONN_STATE_DISCONNECT) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 6bd5322bcf14..4c378af715e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1820,7 +1820,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, conn_state = info->enable ? CONN_STATE_PORT_SECURE : CONN_STATE_DISCONNECT; if (info->link_sta) - mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, info->link_sta, conn_state, info->newly); if (info->link_sta && info->enable) { @@ -1874,7 +1874,7 @@ mt7925_mcu_mlo_sta_cmd(struct mt76_phy *phy, return PTR_ERR(skb); if (info->enable) - mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, info->link_sta, info->enable, info->newly); @@ -1920,6 +1920,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct mt76_sta_cmd_info info = { .link_sta = link_sta, .vif = vif, + .link_conf = &vif->bss_conf, .enable = enable, .cmd = MCU_UNI_CMD(STA_REC_UPDATE), .state = state, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index e9d449bd55ef..8ae98b724668 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2174,7 +2174,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, link_sta, + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf, link_sta, conn_state, newly); if (conn_state == CONN_STATE_DISCONNECT) -- 2.51.0 From 4b98d4aec74fb6242f3442589e9261b7c2f347cd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:04 +0100 Subject: [PATCH 09/16] wifi: mt76: mt7996: prepare mt7996_mcu_update_bss_color for MLO support Pass in struct mt76_vif_link in order to update the correct link. Link: https://patch.msgid.link/20250102163508.52945-20-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/main.c | 34 +++++-------------- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 6 ++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 95d915045cf7..ab875abfbd0a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -540,29 +540,6 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&dev->mt76.mutex); } -static void -mt7996_update_bss_color(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_he_bss_color *bss_color) -{ - struct mt7996_dev *dev = mt7996_hw_dev(hw); - - switch (vif->type) { - case NL80211_IFTYPE_AP: { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - - if (mvif->deflink.mt76.omac_idx > HW_BSSID_MAX) - return; - fallthrough; - } - case NL80211_IFTYPE_STATION: - mt7996_mcu_update_bss_color(dev, vif, bss_color); - break; - default: - break; - } -} - static u8 mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool beacon, bool mcast) @@ -618,9 +595,9 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u64 changed) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt76_vif_link *mvif = mt76_vif_conf_link(&dev->mt76, vif, info); mutex_lock(&dev->mt76.mutex); @@ -662,8 +639,13 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_HE_OBSS_PD) mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); - if (changed & BSS_CHANGED_HE_BSS_COLOR) - mt7996_update_bss_color(hw, vif, &info->he_bss_color); + if (changed & BSS_CHANGED_HE_BSS_COLOR) { + if ((vif->type == NL80211_IFTYPE_AP && + mvif->omac_idx <= HW_BSSID_MAX) || + vif->type == NL80211_IFTYPE_STATION) + mt7996_mcu_update_bss_color(dev, mvif, + &info->he_bss_color); + } if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 8ae98b724668..83c079debf9a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4143,16 +4143,16 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif, return mt7996_mcu_set_obss_spr_bitmap(phy, he_obss_pd); } -int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, + struct mt76_vif_link *mlink, struct cfg80211_he_bss_color *he_bss_color) { int len = sizeof(struct bss_req_hdr) + sizeof(struct bss_color_tlv); - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct bss_color_tlv *bss_color; struct sk_buff *skb; struct tlv *tlv; - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, len); + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, len); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 604b67ea12e4..0774ffdde65d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -531,7 +531,8 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, bool add); -int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, + struct mt76_vif_link *mlink, struct cfg80211_he_bss_color *he_bss_color); int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); -- 2.51.0 From a0facfc80ec12e1fe0bb2407bf9970128d167193 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 2 Jan 2025 17:35:05 +0100 Subject: [PATCH 10/16] wifi: mt76: connac: rework connac helpers Rework connac helpers related to rate and phymode. This is a preliminary patch to add MLO support for mt7996 chipsets. Co-developed-by: Bo Jiao Signed-off-by: Bo Jiao Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250102163508.52945-21-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 2 +- .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 16 ++++++++-------- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 6 +++--- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 16 +++++++--------- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 445d0f0ab779..f7766a9815fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -427,7 +427,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed); u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, bool beacon, bool mcast); bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid, __le32 *txs_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 5170af3e3428..6d30f4fc3526 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -291,28 +291,28 @@ EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues); }) u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, bool beacon, bool mcast) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_link *mvif = mt76_vif_conf_link(mphy->dev, conf->vif, conf); struct cfg80211_chan_def *chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef; u8 nss = 0, mode = 0, band = chandef->chan->band; int rateidx = 0, mcast_rate; int offset = 0; - if (!vif) + if (!conf) goto legacy; if (is_mt7921(mphy->dev)) { - rateidx = ffs(vif->bss_conf.basic_rates) - 1; + rateidx = ffs(conf->basic_rates) - 1; goto legacy; } if (beacon) { struct cfg80211_bitrate_mask *mask; - mask = &vif->bss_conf.beacon_tx_rate; + mask = &conf->beacon_tx_rate; __bitrate_mask_check(he_mcs, HE_SU); __bitrate_mask_check(vht_mcs, VHT); @@ -324,11 +324,11 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, } } - mcast_rate = vif->bss_conf.mcast_rate[band]; + mcast_rate = conf->mcast_rate[band]; if (mcast && mcast_rate > 0) rateidx = mcast_rate - 1; else - rateidx = ffs(vif->bss_conf.basic_rates) - 1; + rateidx = ffs(conf->basic_rates) - 1; legacy: if (band != NL80211_BAND_2GHZ) @@ -581,7 +581,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; bool multicast = ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1); - u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, + u16 rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon, multicast); u32 val = MT_TXD6_FIXED_BW; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 6e52e184aa20..e9ec9b7e0acb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1371,7 +1371,7 @@ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode); -u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, +u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf, enum nl80211_band band) { const struct ieee80211_sta_eht_cap *eht_cap; @@ -1382,9 +1382,9 @@ u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, mode |= PHY_MODE_AX_6G; sband = phy->hw->wiphy->bands[band]; - eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); + eht_cap = ieee80211_get_eht_iftype_cap(sband, conf->vif->type); - if (!eht_cap || !eht_cap->has_eht || !vif->bss_conf.eht_support) + if (!eht_cap || !eht_cap->has_eht || !conf->eht_support) return mode; switch (band) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 541b3c17168b..894b27cb6185 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -2018,7 +2018,7 @@ mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif); u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, enum nl80211_band band, struct ieee80211_link_sta *sta); -u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, +u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf, enum nl80211_band band); int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 4aec10e94178..63a083f9a45c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -805,7 +805,7 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 rate; u8 i, idx, ht; - rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); + rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon, mcast); ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; if (beacon && ht) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index ab875abfbd0a..1bf45888ea1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -541,19 +541,17 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw, } static u8 -mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +mt7996_get_rates_table(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf, bool beacon, bool mcast) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; - struct mt76_phy *mphy = hw->priv; + struct mt7996_dev *dev = phy->dev; + struct mt76_vif_link *mvif = mt76_vif_conf_link(&dev->mt76, conf->vif, conf); u16 rate; u8 i, idx; - rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); + rate = mt76_connac2_mac_tx_rate_val(phy->mt76, conf, beacon, mcast); if (beacon) { - struct mt7996_phy *phy = mphy->priv; - /* odd index for driver, even index for firmware */ idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx; if (phy->beacon_rate != rate) @@ -626,11 +624,11 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_MCAST_RATE) mvif->mcast_rates_idx = - mt7996_get_rates_table(hw, vif, false, true); + mt7996_get_rates_table(phy, info, false, true); if (changed & BSS_CHANGED_BASIC_RATES) mvif->basic_rates_idx = - mt7996_get_rates_table(hw, vif, false, false); + mt7996_get_rates_table(phy, info, false, false); /* ensure that enable txcmd_mode after bss_info */ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) @@ -650,7 +648,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { mvif->beacon_rates_idx = - mt7996_get_rates_table(hw, vif, true, false); + mt7996_get_rates_table(phy, info, true, false); mt7996_mcu_add_beacon(hw, vif, info); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 83c079debf9a..ada019e44712 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1039,7 +1039,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, bss->dtim_period = vif->bss_conf.dtim_period; bss->phymode = mt76_connac_get_phy_mode(phy, vif, chandef->chan->band, NULL); - bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, vif, + bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, &vif->bss_conf, chandef->chan->band); return 0; -- 2.51.0 From 1f8dd5686e6578aa38e90836a275ef2ad3f27d86 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:06 +0100 Subject: [PATCH 11/16] wifi: mt76: mt7996: move all debugfs files to the primary phy Preparation for single-wiphy support Link: https://patch.msgid.link/20250102163508.52945-22-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/debugfs.c | 144 +++++++++++------- .../net/wireless/mediatek/mt76/mt7996/init.c | 6 +- .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 3 files changed, 89 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 335699405ac7..7b2bb72b407d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -51,12 +51,10 @@ static ssize_t mt7996_sys_recovery_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct mt7996_phy *phy = file->private_data; - struct mt7996_dev *dev = phy->dev; - bool band = phy->mt76->band_idx; - char buf[16]; + struct mt7996_dev *dev = file->private_data; + char buf[16], *sep; int ret = 0; - u16 val; + u16 band, val; if (count >= sizeof(buf)) return -EINVAL; @@ -69,21 +67,26 @@ mt7996_sys_recovery_set(struct file *file, const char __user *user_buf, else buf[count] = '\0'; - if (kstrtou16(buf, 0, &val)) + sep = strchr(buf, ','); + if (!sep) + return -EINVAL; + + *sep = 0; + if (kstrtou16(buf, 0, &band) || kstrtou16(sep + 1, 0, &val)) return -EINVAL; switch (val) { /* - * 0: grab firmware current SER state. - * 1: trigger & enable system error L1 recovery. - * 2: trigger & enable system error L2 recovery. - * 3: trigger & enable system error L3 rx abort. - * 4: trigger & enable system error L3 tx abort - * 5: trigger & enable system error L3 tx disable. - * 6: trigger & enable system error L3 bf recovery. - * 7: trigger & enable system error L4 mdp recovery. - * 8: trigger & enable system error full recovery. - * 9: trigger firmware crash. + * ,0: grab firmware current SER state. + * ,1: trigger & enable system error L1 recovery. + * ,2: trigger & enable system error L2 recovery. + * ,3: trigger & enable system error L3 rx abort. + * ,4: trigger & enable system error L3 tx abort + * ,5: trigger & enable system error L3 tx disable. + * ,6: trigger & enable system error L3 bf recovery. + * ,7: trigger & enable system error L4 mdp recovery. + * ,8: trigger & enable system error full recovery. + * ,9: trigger firmware crash. */ case UNI_CMD_SER_QUERY: ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_QUERY, 0, band); @@ -126,8 +129,7 @@ static ssize_t mt7996_sys_recovery_get(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct mt7996_phy *phy = file->private_data; - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = file->private_data; char *buff; int desc = 0; ssize_t ret; @@ -141,25 +143,25 @@ mt7996_sys_recovery_get(struct file *file, char __user *user_buf, desc += scnprintf(buff + desc, bufsz - desc, "Please echo the correct value ...\n"); desc += scnprintf(buff + desc, bufsz - desc, - "0: grab firmware transient SER state\n"); + ",0: grab firmware transient SER state\n"); desc += scnprintf(buff + desc, bufsz - desc, - "1: trigger system error L1 recovery\n"); + ",1: trigger system error L1 recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "2: trigger system error L2 recovery\n"); + ",2: trigger system error L2 recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "3: trigger system error L3 rx abort\n"); + ",3: trigger system error L3 rx abort\n"); desc += scnprintf(buff + desc, bufsz - desc, - "4: trigger system error L3 tx abort\n"); + ",4: trigger system error L3 tx abort\n"); desc += scnprintf(buff + desc, bufsz - desc, - "5: trigger system error L3 tx disable\n"); + ",5: trigger system error L3 tx disable\n"); desc += scnprintf(buff + desc, bufsz - desc, - "6: trigger system error L3 bf recovery\n"); + ",6: trigger system error L3 bf recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "7: trigger system error L4 mdp recovery\n"); + ",7: trigger system error L4 mdp recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "8: trigger system error full recovery\n"); + ",8: trigger system error full recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "9: trigger firmware crash\n"); + ",9: trigger firmware crash\n"); /* SER statistics */ desc += scnprintf(buff + desc, bufsz - desc, @@ -524,16 +526,12 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) seq_puts(s, "\n"); } -static int -mt7996_tx_stats_show(struct seq_file *file, void *data) +static void +mt7996_tx_stats_show_phy(struct seq_file *file, struct mt7996_phy *phy) { - struct mt7996_phy *phy = file->private; - struct mt7996_dev *dev = phy->dev; struct mt76_mib_stats *mib = &phy->mib; - int i; u32 attempts, success, per; - - mutex_lock(&dev->mt76.mutex); + int i; mt7996_mac_update_stats(phy); mt7996_ampdu_stat_read_phy(phy, file); @@ -558,6 +556,23 @@ mt7996_tx_stats_show(struct seq_file *file, void *data) else seq_puts(file, "\n"); } +} + +static int +mt7996_tx_stats_show(struct seq_file *file, void *data) +{ + struct mt7996_dev *dev = file->private; + struct mt7996_phy *phy = &dev->phy; + + mutex_lock(&dev->mt76.mutex); + + mt7996_tx_stats_show_phy(file, phy); + phy = mt7996_phy2(dev); + if (phy) + mt7996_tx_stats_show_phy(file, phy); + phy = mt7996_phy3(dev); + if (phy) + mt7996_tx_stats_show_phy(file, phy); mutex_unlock(&dev->mt76.mutex); @@ -628,8 +643,8 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) static int mt7996_hw_queues_show(struct seq_file *file, void *data) { - struct mt7996_phy *phy = file->private; - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = file->private; + struct mt7996_phy *phy = &dev->phy; static const struct hw_queue_map ple_queue_map[] = { { "CPU_Q0", 0, 1, MT_CTX0 }, { "CPU_Q1", 1, 1, MT_CTX0 + 1 }, @@ -685,6 +700,15 @@ mt7996_hw_queues_show(struct seq_file *file, void *data) /* iterate per-sta ple queue */ ieee80211_iterate_stations_atomic(phy->mt76->hw, mt7996_sta_hw_queue_read, file); + phy = mt7996_phy2(dev); + if (phy) + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7996_sta_hw_queue_read, file); + phy = mt7996_phy3(dev); + if (phy) + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7996_sta_hw_queue_read, file); + /* pse queue */ seq_puts(file, "PSE non-empty queue info:\n"); mt7996_hw_queue_read(file, ARRAY_SIZE(pse_queue_map), @@ -698,19 +722,29 @@ DEFINE_SHOW_ATTRIBUTE(mt7996_hw_queues); static int mt7996_xmit_queues_show(struct seq_file *file, void *data) { - struct mt7996_phy *phy = file->private; - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = file->private; + struct mt7996_phy *phy; struct { struct mt76_queue *q; char *queue; } queue_map[] = { - { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" }, + { dev->mphy.q_tx[MT_TXQ_BE], " MAIN0" }, + { NULL, " MAIN1" }, + { NULL, " MAIN2" }, { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" }, { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" }, { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" }, }; int i; + phy = mt7996_phy2(dev); + if (phy) + queue_map[1].q = phy->mt76->q_tx[MT_TXQ_BE]; + + phy = mt7996_phy3(dev); + if (phy) + queue_map[2].q = phy->mt76->q_tx[MT_TXQ_BE]; + seq_puts(file, " queue | hw-queued | head | tail |\n"); for (i = 0; i < ARRAY_SIZE(queue_map); i++) { struct mt76_queue *q = queue_map[i].q; @@ -785,20 +819,20 @@ mt7996_rf_regval_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7996_rf_regval_get, mt7996_rf_regval_set, "0x%08llx\n"); -int mt7996_init_debugfs(struct mt7996_phy *phy) +int mt7996_init_debugfs(struct mt7996_dev *dev) { - struct mt7996_dev *dev = phy->dev; struct dentry *dir; - dir = mt76_register_debugfs_fops(phy->mt76, NULL); + dir = mt76_register_debugfs_fops(&dev->mphy, NULL); if (!dir) return -ENOMEM; - debugfs_create_file("hw-queues", 0400, dir, phy, + + debugfs_create_file("hw-queues", 0400, dir, dev, &mt7996_hw_queues_fops); - debugfs_create_file("xmit-queues", 0400, dir, phy, + debugfs_create_file("xmit-queues", 0400, dir, dev, &mt7996_xmit_queues_fops); - debugfs_create_file("tx_stats", 0400, dir, phy, &mt7996_tx_stats_fops); - debugfs_create_file("sys_recovery", 0600, dir, phy, + debugfs_create_file("tx_stats", 0400, dir, dev, &mt7996_tx_stats_fops); + debugfs_create_file("sys_recovery", 0600, dir, dev, &mt7996_sys_recovery_ops); debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); @@ -812,17 +846,13 @@ int mt7996_init_debugfs(struct mt7996_phy *phy) mt7996_twt_stats); debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); - if (phy->mt76->cap.has_5ghz) { - debugfs_create_u32("dfs_hw_pattern", 0400, dir, - &dev->hw_pattern); - debugfs_create_file("radar_trigger", 0200, dir, dev, - &fops_radar_trigger); - debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, - mt7996_rdd_monitor); - } + debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + debugfs_create_file("radar_trigger", 0200, dir, dev, + &fops_radar_trigger); + debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, + mt7996_rdd_monitor); - if (phy == &dev->phy) - dev->debugfs_dir = dir; + dev->debugfs_dir = dir; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 400950aab9a9..124c73bb4a28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -630,10 +630,6 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; - ret = mt7996_init_debugfs(phy); - if (ret) - goto error; - if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; @@ -1458,7 +1454,7 @@ int mt7996_register_device(struct mt7996_dev *dev) dev->recovery.hw_init_done = true; - ret = mt7996_init_debugfs(&dev->phy); + ret = mt7996_init_debugfs(dev); if (ret) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 0774ffdde65d..f1384e4e7e7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -680,7 +680,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy); void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy); void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy); void mt7996_update_channel(struct mt76_phy *mphy); -int mt7996_init_debugfs(struct mt7996_phy *phy); +int mt7996_init_debugfs(struct mt7996_dev *dev); void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len); bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len); int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, -- 2.51.0 From 69d54ce7491d046eaae05de7fb2493319a481991 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:07 +0100 Subject: [PATCH 12/16] wifi: mt76: mt7996: switch to single multi-radio wiphy Use generic mt76 chanctx functions and look up phy from vif link. The driver now uses only a single phy to handle multiple interfaces on different channels. This is preparation for full MLO support. Link: https://patch.msgid.link/20250102163508.52945-23-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/eeprom.c | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 244 ++++--- .../net/wireless/mediatek/mt76/mt7996/mac.c | 6 +- .../net/wireless/mediatek/mt76/mt7996/main.c | 651 +++++++++++------- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 15 +- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 3 + .../wireless/mediatek/mt76/mt7996/mt7996.h | 52 +- 7 files changed, 593 insertions(+), 379 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index da94751df020..53dfac02f8af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -305,6 +305,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) mphy->antenna_mask = BIT(nss) - 1; mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx]; + phy->orig_chainmask = mphy->chainmask; dev->chainmask |= mphy->chainmask; if (band_idx < MT_BAND2) dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] + diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 124c73bb4a28..d5337ceb9dc5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -14,6 +14,28 @@ #include "coredump.h" #include "eeprom.h" +static const struct ieee80211_iface_limit if_limits_global = { + .max = MT7996_MAX_INTERFACES * MT7996_MAX_RADIOS, + .types = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) + | BIT(NL80211_IFTYPE_AP) +#ifdef CONFIG_MAC80211_MESH + | BIT(NL80211_IFTYPE_MESH_POINT) +#endif +}; + +static const struct ieee80211_iface_combination if_comb_global = { + .limits = &if_limits_global, + .n_limits = 1, + .max_interfaces = MT7996_MAX_INTERFACES * MT7996_MAX_RADIOS, + .num_different_channels = MT7996_MAX_RADIOS, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), +}; + static const struct ieee80211_iface_limit if_limits[] = { { .max = 16, @@ -27,20 +49,18 @@ static const struct ieee80211_iface_limit if_limits[] = { } }; -static const struct ieee80211_iface_combination if_comb[] = { - { - .limits = if_limits, - .n_limits = ARRAY_SIZE(if_limits), - .max_interfaces = MT7996_MAX_INTERFACES, - .num_different_channels = 1, - .beacon_int_infra_match = true, - .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80) | - BIT(NL80211_CHAN_WIDTH_160), - .beacon_int_min_gcd = 100, - } +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = MT7996_MAX_INTERFACES, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), + .beacon_int_min_gcd = 100, }; static ssize_t mt7996_thermal_temp_show(struct device *dev, @@ -177,28 +197,32 @@ static const struct thermal_cooling_device_ops mt7996_thermal_ops = { static void mt7996_unregister_thermal(struct mt7996_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; + char name[sizeof("cooling_deviceXXX")]; if (!phy->cdev) return; - sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); + snprintf(name, sizeof(name), "cooling_device%d", phy->mt76->band_idx); + sysfs_remove_link(&wiphy->dev.kobj, name); thermal_cooling_device_unregister(phy->cdev); } static int mt7996_thermal_init(struct mt7996_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; + char cname[sizeof("cooling_deviceXXX")]; struct thermal_cooling_device *cdev; struct device *hwmon; const char *name; - name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s", - wiphy_name(wiphy)); + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s.%d", + wiphy_name(wiphy), phy->mt76->band_idx); + snprintf(cname, sizeof(cname), "cooling_device%d", phy->mt76->band_idx); cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops); if (!IS_ERR(cdev)) { if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, - "cooling_device") < 0) + cname) < 0) thermal_cooling_device_unregister(cdev); else phy->cdev = cdev; @@ -330,28 +354,88 @@ mt7996_regd_notifier(struct wiphy *wiphy, { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy; memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; - if (dev->mt76.region == NL80211_DFS_UNSET) - mt7996_mcu_rdd_background_enable(phy, NULL); + mt7996_for_each_phy(dev, phy) { + if (dev->mt76.region == NL80211_DFS_UNSET) + mt7996_mcu_rdd_background_enable(phy, NULL); - mt7996_init_txpower(phy); + mt7996_init_txpower(phy); + phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; + mt7996_dfs_init_radar_detector(phy); + } +} + +static void +mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy) +{ + struct mt7996_dev *dev = phy->dev; + struct wiphy *wiphy = hw->wiphy; + int n_radios = hw->wiphy->n_radio; + struct wiphy_radio_freq_range *freq = &dev->radio_freqs[n_radios]; + struct wiphy_radio *radio = &dev->radios[n_radios]; + + phy->slottime = 9; + phy->beacon_rate = -1; + + if (phy->mt76->cap.has_2ghz) { + phy->mt76->sband_2g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + phy->mt76->sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_2; + freq->start_freq = 2400000; + freq->end_freq = 2500000; + } else if (phy->mt76->cap.has_5ghz) { + phy->mt76->sband_5g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + + phy->mt76->sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + phy->mt76->sband_5g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_1; + + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + freq->start_freq = 5000000; + freq->end_freq = 5900000; + } else if (phy->mt76->cap.has_6ghz) { + freq->start_freq = 5900000; + freq->end_freq = 7200000; + } else { + return; + } + + dev->radio_phy[n_radios] = phy; + radio->freq_range = freq; + radio->n_freq_range = 1; + radio->iface_combinations = &if_comb; + radio->n_iface_combinations = 1; + hw->wiphy->n_radio++; - phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; - mt7996_dfs_init_radar_detector(phy); + wiphy->available_antennas_rx |= phy->mt76->chainmask; + wiphy->available_antennas_tx |= phy->mt76->chainmask; + + mt76_set_stream_caps(phy->mt76, true); + mt7996_set_stream_vht_txbf_caps(phy); + mt7996_set_stream_he_eht_caps(phy); + mt7996_init_txpower(phy); } static void mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt76_dev *mdev = &phy->dev->mt76; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt76_dev *mdev = &dev->mt76; struct wiphy *wiphy = hw->wiphy; - u16 max_subframes = phy->dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT : - IEEE80211_MAX_AMPDU_BUF_HE; + u16 max_subframes = dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT : + IEEE80211_MAX_AMPDU_BUF_HE; hw->queues = 4; hw->max_rx_aggregation_subframes = max_subframes; @@ -363,14 +447,15 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; - phy->slottime = 9; - phy->beacon_rate = -1; - hw->sta_data_size = sizeof(struct mt7996_sta); hw->vif_data_size = sizeof(struct mt7996_vif); + hw->chanctx_data_size = sizeof(struct mt76_chanctx); + + wiphy->iface_combinations = &if_comb_global; + wiphy->n_iface_combinations = 1; + + wiphy->radio = dev->radios; - wiphy->iface_combinations = if_comb; - wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->reg_notifier = mt7996_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; wiphy->mbssid_max_interfaces = 16; @@ -387,7 +472,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); - if (mt7996_has_background_radar(phy->dev) && + if (mt7996_has_background_radar(dev) && (!mdev->dev->of_node || !of_property_read_bool(mdev->dev->of_node, "mediatek,disable-radar-background"))) @@ -397,51 +482,21 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); - ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); hw->max_tx_fragments = 4; - if (phy->mt76->cap.has_2ghz) { - phy->mt76->sband_2g.sband.ht_cap.cap |= - IEEE80211_HT_CAP_LDPC_CODING | - IEEE80211_HT_CAP_MAX_AMSDU; - phy->mt76->sband_2g.sband.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_2; - } - - if (phy->mt76->cap.has_5ghz) { - phy->mt76->sband_5g.sband.ht_cap.cap |= - IEEE80211_HT_CAP_LDPC_CODING | - IEEE80211_HT_CAP_MAX_AMSDU; - - phy->mt76->sband_5g.sband.vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | - IEEE80211_VHT_CAP_SHORT_GI_160 | - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - phy->mt76->sband_5g.sband.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_1; - - ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); - } - /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { - phy->mt76->leds.cdev.brightness_set = mt7996_led_set_brightness; - phy->mt76->leds.cdev.blink_set = mt7996_led_set_blink; + dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness; + dev->mphy.leds.cdev.blink_set = mt7996_led_set_blink; } - mt76_set_stream_caps(phy->mt76, true); - mt7996_set_stream_vht_txbf_caps(phy); - mt7996_set_stream_he_eht_caps(phy); - mt7996_init_txpower(phy); - - wiphy->available_antennas_rx = phy->mt76->antenna_mask; - wiphy->available_antennas_tx = phy->mt76->antenna_mask; - wiphy->max_scan_ssids = 4; wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + + mt7996_init_wiphy_band(hw, &dev->phy); } static void @@ -562,18 +617,15 @@ int mt7996_txbf_init(struct mt7996_dev *dev) return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE); } -static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, - enum mt76_band_id band) +static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) { + struct mt7996_phy *phy; struct mt76_phy *mphy; u32 mac_ofs, hif1_ofs = 0; int ret; struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (!mt7996_band_valid(dev, band) || band == MT_BAND0) - return 0; - - if (phy) + if (!mt7996_band_valid(dev, band)) return 0; if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) { @@ -581,7 +633,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, wed = &dev->mt76.mmio.wed_hif2; } - mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band); + mphy = mt76_alloc_radio_phy(&dev->mt76, sizeof(*phy), band); if (!mphy) return -ENOMEM; @@ -612,7 +664,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ - mt7996_init_wiphy(mphy->hw, wed); + mt7996_init_wiphy_band(mphy->hw, phy); ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), MT7996_TX_RING_SIZE, @@ -626,10 +678,6 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; - ret = mt7996_thermal_init(phy); - if (ret) - goto error; - if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; @@ -641,24 +689,14 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, error: mphy->dev->phys[band] = NULL; - ieee80211_free_hw(mphy->hw); return ret; } static void -mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) +mt7996_unregister_phy(struct mt7996_phy *phy) { - struct mt76_phy *mphy; - - if (!phy) - return; - - mt7996_unregister_thermal(phy); - - mphy = phy->dev->mt76.phys[band]; - mt76_unregister_phy(mphy); - ieee80211_free_hw(mphy->hw); - phy->dev->mt76.phys[band] = NULL; + if (phy) + mt7996_unregister_thermal(phy); } static void mt7996_init_work(struct work_struct *work) @@ -1412,6 +1450,7 @@ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy) int mt7996_register_device(struct mt7996_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); + struct mt7996_phy *phy; int ret; dev->phy.dev = dev; @@ -1433,22 +1472,21 @@ int mt7996_register_device(struct mt7996_dev *dev) mt7996_init_wiphy(hw, &dev->mt76.mmio.wed); - ret = mt76_register_device(&dev->mt76, true, mt76_rates, - ARRAY_SIZE(mt76_rates)); + ret = mt7996_register_phy(dev, MT_BAND1); if (ret) return ret; - ret = mt7996_thermal_init(&dev->phy); + ret = mt7996_register_phy(dev, MT_BAND2); if (ret) return ret; - ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) return ret; - ret = mt7996_register_phy(dev, mt7996_phy3(dev), MT_BAND2); - if (ret) - return ret; + mt7996_for_each_phy(dev, phy) + mt7996_thermal_init(phy); ieee80211_queue_work(mt76_hw(dev), &dev->init_work); @@ -1473,8 +1511,8 @@ error: void mt7996_unregister_device(struct mt7996_dev *dev) { cancel_work_sync(&dev->wed_rro.work); - mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); - mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); + mt7996_unregister_phy(mt7996_phy3(dev)); + mt7996_unregister_phy(mt7996_phy2(dev)); mt7996_unregister_thermal(&dev->phy); mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 89523afa4aca..f5865d9688b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1738,19 +1738,19 @@ mt7996_mac_restart(struct mt7996_dev *dev) ret = mt7996_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { - ret = mt7996_run(dev->mphy.hw); + ret = mt7996_run(&dev->phy); if (ret) goto out; } if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) { - ret = mt7996_run(phy2->mt76->hw); + ret = mt7996_run(phy2); if (ret) goto out; } if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) { - ret = mt7996_run(phy3->mt76->hw); + ret = mt7996_run(phy3); if (ret) goto out; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 1bf45888ea1e..e8a9394e5437 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -7,76 +7,44 @@ #include "mcu.h" #include "mac.h" -static bool mt7996_dev_running(struct mt7996_dev *dev) +int mt7996_run(struct mt7996_phy *phy) { - struct mt7996_phy *phy; - - if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) - return true; - - phy = mt7996_phy2(dev); - if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) - return true; - - phy = mt7996_phy3(dev); - - return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); -} - -int mt7996_run(struct ieee80211_hw *hw) -{ - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - bool running; + struct mt7996_dev *dev = phy->dev; int ret; - running = mt7996_dev_running(dev); - if (!running) { - ret = mt7996_mcu_set_hdr_trans(dev, true); - if (ret) - goto out; - - if (is_mt7992(&dev->mt76)) { - u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); - - ret = mt7996_mcu_cp_support(dev, queue); - if (ret) - goto out; - } - } - mt7996_mac_enable_nf(dev, phy->mt76->band_idx); ret = mt7996_mcu_set_rts_thresh(phy, 0x92b); if (ret) - goto out; + return ret; ret = mt7996_mcu_set_radio_en(phy, true); if (ret) - goto out; + return ret; ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); if (ret) - goto out; + return ret; ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX); if (ret) - goto out; + return ret; ret = mt7996_mcu_set_thermal_protect(phy, true); if (ret) - goto out; + return ret; set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + ieee80211_queue_delayed_work(dev->mphy.hw, &phy->mt76->mac_work, MT7996_WATCHDOG_TIME); - if (!running) + if (!phy->counter_reset) { mt7996_mac_reset_counters(phy); + phy->counter_reset = true; + } -out: - return ret; + return 0; } static int mt7996_start(struct ieee80211_hw *hw) @@ -87,16 +55,23 @@ static int mt7996_start(struct ieee80211_hw *hw) flush_work(&dev->init_work); mutex_lock(&dev->mt76.mutex); - ret = mt7996_run(hw); + ret = mt7996_mcu_set_hdr_trans(dev, true); + if (!ret && is_mt7992(&dev->mt76)) { + u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); + + ret = mt7996_mcu_cp_support(dev, queue); + } mutex_unlock(&dev->mt76.mutex); return ret; } -static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) +static void mt7996_stop_phy(struct mt7996_phy *phy) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_dev *dev = phy->dev; + + if (!phy || !test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; cancel_delayed_work_sync(&phy->mt76->mac_work); @@ -109,6 +84,10 @@ static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) mutex_unlock(&dev->mt76.mutex); } +static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) +{ +} + static inline int get_free_idx(u32 mask, u8 start, u8 end) { return ffs(~mask & GENMASK(end, start)); @@ -177,46 +156,113 @@ mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlin } static int -mt7996_vif_link_add(struct mt7996_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) +mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct mt7996_vif_link *mlink, struct ieee80211_key_conf *key) { + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : + &mlink->sta; + struct mt76_wcid *wcid = &msta->wcid; + u8 *wcid_keyidx = &wcid->hw_key_idx; + struct mt7996_phy *phy; + int idx = key->keyidx; + + phy = mt7996_vif_link_phy(mlink); + if (!phy) + return -EINVAL; + + if (sta && !wcid->sta) + return -EOPNOTSUPP; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + if (key->keyidx == 6 || key->keyidx == 7) { + wcid_keyidx = &wcid->hw_key_idx2; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + } + break; + default: + break; + } + + if (cmd == SET_KEY && !sta && !mlink->mt76.cipher) { + mlink->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); + mt7996_mcu_add_bss_info(phy, vif, &vif->bss_conf, &mlink->mt76, true); + } + + if (cmd == SET_KEY) { + *wcid_keyidx = idx; + } else { + if (idx == *wcid_keyidx) + *wcid_keyidx = -1; + return 0; + } + + mt76_wcid_key_setup(&dev->mt76, wcid, key); + + if (key->keyidx == 6 || key->keyidx == 7) + return mt7996_mcu_bcn_prot_enable(dev, vif, key); + + return mt7996_mcu_add_key(&dev->mt76, vif, key, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), + &msta->wcid, cmd); +} + +static void +mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct ieee80211_key_conf *key, + void *data) +{ + struct mt7996_vif_link *mlink = data; + + if (sta) + return; + + WARN_ON(mt7996_set_hw_key(hw, SET_KEY, vif, NULL, mlink, key)); +} + +int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink) +{ + struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); + struct mt7996_phy *phy = mphy->priv; struct mt7996_dev *dev = phy->dev; u8 band_idx = phy->mt76->band_idx; - struct mt7996_vif_link *mlink; struct mt76_txq *mtxq; int idx, ret; - mlink = mt7996_vif_conf_link(dev, vif, link_conf); - if (!mlink) - return -EINVAL; - - mlink->mt76.idx = __ffs64(~dev->mt76.vif_mask); - if (mlink->mt76.idx >= mt7996_max_interface_num(dev)) + mlink->idx = __ffs64(~dev->mt76.vif_mask); + if (mlink->idx >= mt7996_max_interface_num(dev)) return -ENOSPC; idx = get_omac_idx(vif->type, phy->omac_mask); if (idx < 0) return -ENOSPC; - mlink->mt76.omac_idx = idx; - mlink->phy = phy; - mlink->mt76.band_idx = band_idx; - mlink->mt76.wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; - mlink->mt76.wcid = &mlink->sta.wcid; + link->phy = phy; + mlink->omac_idx = idx; + mlink->band_idx = band_idx; + mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; + mlink->wcid = &link->sta.wcid; - ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, &mlink->mt76, true); + ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, true); if (ret) return ret; - dev->mt76.vif_mask |= BIT_ULL(mlink->mt76.idx); - phy->omac_mask |= BIT_ULL(mlink->mt76.omac_idx); + dev->mt76.vif_mask |= BIT_ULL(mlink->idx); + phy->omac_mask |= BIT_ULL(mlink->omac_idx); - idx = MT7996_WTBL_RESERVED - mlink->mt76.idx; + idx = MT7996_WTBL_RESERVED - mlink->idx; - INIT_LIST_HEAD(&mlink->sta.rc_list); - mlink->sta.wcid.idx = idx; - mlink->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; - mt76_wcid_init(&mlink->sta.wcid, band_idx); + INIT_LIST_HEAD(&link->sta.rc_list); + link->sta.wcid.idx = idx; + link->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_wcid_init(&link->sta.wcid, band_idx); mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -227,56 +273,50 @@ mt7996_vif_link_add(struct mt7996_phy *phy, struct ieee80211_vif *vif, } if (vif->type != NL80211_IFTYPE_AP && - (!mlink->mt76.omac_idx || mlink->mt76.omac_idx > 3)) + (!mlink->omac_idx || mlink->omac_idx > 3)) vif->offload_flags = 0; if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) - mlink->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; + mlink->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; else - mlink->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL; + mlink->basic_rates_idx = MT7996_BASIC_RATES_TBL; - mt7996_init_bitrate_mask(vif, mlink); + mt7996_init_bitrate_mask(vif, link); - mt7996_mcu_add_bss_info(phy, vif, link_conf, &mlink->mt76, true); + mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, true); /* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA * interface, since firmware only records BSSID when the entry is new */ if (vif->type != NL80211_IFTYPE_STATION) - mt7996_mcu_add_sta(dev, vif, &mlink->mt76, NULL, - CONN_STATE_PORT_SECURE, true); - rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->sta.wcid); + mt7996_mcu_add_sta(dev, vif, mlink, NULL, CONN_STATE_PORT_SECURE, true); + rcu_assign_pointer(dev->mt76.wcid[idx], &link->sta.wcid); + + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, link); return 0; } -static void -mt7996_vif_link_remove(struct mt7996_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) +void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink) { + struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); + struct mt7996_phy *phy = mphy->priv; struct mt7996_dev *dev = phy->dev; - struct mt7996_vif_link *mlink; struct mt7996_sta *msta; int idx; - mlink = mt7996_vif_conf_link(dev, vif, link_conf); - if (!mlink) - return; - - mlink->phy = NULL; - msta = &mlink->sta; + msta = &link->sta; idx = msta->wcid.idx; - mt7996_mcu_add_sta(dev, vif, &mlink->mt76, NULL, CONN_STATE_DISCONNECT, - false); - mt7996_mcu_add_bss_info(phy, vif, link_conf, &mlink->mt76, false); + mt7996_mcu_add_sta(dev, vif, mlink, NULL, CONN_STATE_DISCONNECT, false); + mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, false); - mt7996_mcu_add_dev_info(phy, vif, link_conf, &mlink->mt76, false); + mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - mutex_lock(&dev->mt76.mutex); - dev->mt76.vif_mask &= ~BIT_ULL(mlink->mt76.idx); - phy->omac_mask &= ~BIT_ULL(mlink->mt76.omac_idx); - mutex_unlock(&dev->mt76.mutex); + dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); + phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) @@ -286,34 +326,121 @@ mt7996_vif_link_remove(struct mt7996_phy *phy, struct ieee80211_vif *vif, mt76_wcid_cleanup(&dev->mt76, &msta->wcid); } +static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) +{ + struct mt7996_dev *dev = phy->dev; + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; + u32 filter = phy->rxfilter; + + if (filter & MT_WF_RFCR_DROP_OTHER_UC) { + filter |= MT_WF_RFCR_DROP_CTS | + MT_WF_RFCR_DROP_RTS | + MT_WF_RFCR_DROP_CTL_RSV | + MT_WF_RFCR_DROP_FCSFAIL; + } + + mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), filter); + if (filter & MT_WF_RFCR_DROP_CTL_RSV) + mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); + else + mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); +} + +static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) +{ + struct mt7996_dev *dev = phy->dev; + + if (!phy) + return; + + if (enabled == !(phy->rxfilter & MT_WF_RFCR_DROP_OTHER_UC)) + return; + + if (!enabled) + phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + else + phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + + mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), + MT_DMA_DCR0_RXD_G5_EN, enabled); + mt7996_phy_set_rxfilter(phy); +} + static int mt7996_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int ret = 0; + int i, err = 0; mutex_lock(&dev->mt76.mutex); + for (i = 0; i < MT7996_MAX_RADIOS; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + if (!phy || !(wdev->radio_mask & BIT(i)) || + test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + continue; + + err = mt7996_run(phy); + if (err) + goto out; + + if (vif->type == NL80211_IFTYPE_MONITOR) + mt7996_set_monitor(phy, true); + } + mt76_vif_init(vif, &mvif->mt76); vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; - ret = mt7996_vif_link_add(phy, vif, &vif->bss_conf); +out: mutex_unlock(&dev->mt76.mutex); - return ret; + return err; +} + +struct mt7996_radio_data { + u32 active_mask; + u32 monitor_mask; +}; + +static void mt7996_remove_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); + struct mt7996_radio_data *rdata = data; + + rdata->active_mask |= wdev->radio_mask; + if (vif->type == NL80211_IFTYPE_MONITOR) + rdata->monitor_mask |= wdev->radio_mask; } static void mt7996_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_radio_data rdata = {}; + int i; - mt7996_vif_link_remove(phy, vif, &vif->bss_conf); + ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, + &rdata); mt76_vif_cleanup(&dev->mt76, vif); + + for (i = 0; i < MT7996_MAX_RADIOS; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + if (!phy) + continue; + if (!(rdata.monitor_mask & BIT(i))) + mt7996_set_monitor(phy, false); + if (!(rdata.active_mask & BIT(i))) + mt7996_stop_phy(phy); + } } int mt7996_set_channel(struct mt76_phy *mphy) @@ -329,6 +456,10 @@ int mt7996_set_channel(struct mt76_phy *mphy) if (ret) goto out; + ret = mt7996_mcu_set_txpower_sku(phy); + if (ret) + goto out; + ret = mt7996_dfs_init_radar_detector(phy); mt7996_mac_cca_stats_reset(phy); @@ -347,15 +478,9 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_vif_link *mlink = &mvif->deflink; - struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : - &mlink->sta; - struct mt76_wcid *wcid = &msta->wcid; - u8 *wcid_keyidx = &wcid->hw_key_idx; - int idx = key->keyidx; - int err = 0; + int err; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. @@ -367,9 +492,6 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; - if (sta && !wcid->sta) - return -EOPNOTSUPP; - /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: @@ -383,11 +505,8 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: - if (key->keyidx == 6 || key->keyidx == 7) { - wcid_keyidx = &wcid->hw_key_idx2; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + if (key->keyidx == 6 || key->keyidx == 7) break; - } fallthrough; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -395,31 +514,11 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } - mutex_lock(&dev->mt76.mutex); - - if (cmd == SET_KEY && !sta && !mlink->mt76.cipher) { - mlink->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); - mt7996_mcu_add_bss_info(phy, vif, &vif->bss_conf, &mlink->mt76, - true); - } - - if (cmd == SET_KEY) { - *wcid_keyidx = idx; - } else { - if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - goto out; - } - - mt76_wcid_key_setup(&dev->mt76, wcid, key); + if (!mt7996_vif_link_phy(mlink)) + return 0; /* defer until after link add */ - if (key->keyidx == 6 || key->keyidx == 7) - err = mt7996_mcu_bcn_prot_enable(dev, vif, key); - else - err = mt7996_mcu_add_key(&dev->mt76, vif, key, - MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); -out: + mutex_lock(&dev->mt76.mutex); + err = mt7996_set_hw_key(hw, cmd, vif, sta, mlink, key); mutex_unlock(&dev->mt76.mutex); return err; @@ -427,40 +526,6 @@ out: static int mt7996_config(struct ieee80211_hw *hw, u32 changed) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int ret; - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = mt76_update_channel(phy->mt76); - if (ret) - return ret; - } - - if (changed & (IEEE80211_CONF_CHANGE_POWER | - IEEE80211_CONF_CHANGE_CHANNEL)) { - ret = mt7996_mcu_set_txpower_sku(phy); - if (ret) - return ret; - } - - mutex_lock(&dev->mt76.mutex); - - if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); - - if (!enabled) - phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; - else - phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; - - mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), - MT_DMA_DCR0_RXD_G5_EN, enabled); - mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); - } - - mutex_unlock(&dev->mt76.mutex); - return 0; } @@ -491,34 +556,18 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | - MT_WF_RFCR1_DROP_BF_POLL | - MT_WF_RFCR1_DROP_BA | - MT_WF_RFCR1_DROP_CFEND | - MT_WF_RFCR1_DROP_CFACK; + struct mt7996_phy *phy; + u32 filter_mask = 0, filter_set = 0; u32 flags = 0; -#define MT76_FILTER(_flag, _hw) do { \ - flags |= *total_flags & FIF_##_flag; \ - phy->rxfilter &= ~(_hw); \ - phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + filter_mask |= (_hw); \ + filter_set |= !(flags & FIF_##_flag) * (_hw); \ } while (0) mutex_lock(&dev->mt76.mutex); - phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | - MT_WF_RFCR_DROP_OTHER_BEACON | - MT_WF_RFCR_DROP_FRAME_REPORT | - MT_WF_RFCR_DROP_PROBEREQ | - MT_WF_RFCR_DROP_MCAST_FILTERED | - MT_WF_RFCR_DROP_MCAST | - MT_WF_RFCR_DROP_BCAST | - MT_WF_RFCR_DROP_DUPLICATE | - MT_WF_RFCR_DROP_A2_BSSID | - MT_WF_RFCR_DROP_UNWANTED_CTL | - MT_WF_RFCR_DROP_STBC_MULTI); - MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | MT_WF_RFCR_DROP_A3_MAC | MT_WF_RFCR_DROP_A3_BSSID); @@ -530,12 +579,23 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw, MT_WF_RFCR_DROP_CTL_RSV); *total_flags = flags; - mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); - if (*total_flags & FIF_CONTROL) - mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); - else - mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); + mt7996_for_each_phy(dev, phy) { + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | + MT_WF_RFCR_DROP_OTHER_BEACON | + MT_WF_RFCR_DROP_FRAME_REPORT | + MT_WF_RFCR_DROP_PROBEREQ | + MT_WF_RFCR_DROP_MCAST_FILTERED | + MT_WF_RFCR_DROP_MCAST | + MT_WF_RFCR_DROP_BCAST | + MT_WF_RFCR_DROP_DUPLICATE | + MT_WF_RFCR_DROP_A2_BSSID | + MT_WF_RFCR_DROP_UNWANTED_CTL | + MT_WF_RFCR_DROP_STBC_MULTI | + filter_mask); + phy->rxfilter |= filter_set; + mt7996_phy_set_rxfilter(phy); + } mutex_unlock(&dev->mt76.mutex); } @@ -593,12 +653,23 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u64 changed) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt76_vif_link *mvif = mt76_vif_conf_link(&dev->mt76, vif, info); + struct mt76_vif_link *mvif; + struct mt7996_phy *phy; + struct mt76_phy *mphy; mutex_lock(&dev->mt76.mutex); + mvif = mt76_vif_conf_link(&dev->mt76, vif, info); + if (!mvif) + goto out; + + mphy = mt76_vif_link_phy(mvif); + if (!mphy) + goto out; + + phy = mphy->priv; + /* station mode uses BSSID to map the wlan entry to a peer, * and then peer references bss_info_rfch to set bandwidth cap. */ @@ -660,6 +731,13 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_MU_GROUPS) mt7996_update_mu_group(hw, vif, info); + if (changed & BSS_CHANGED_TXPOWER && + info->txpower != phy->txpower) { + phy->txpower = info->txpower; + mt7996_mcu_set_txpower_sku(phy); + } + +out: mutex_unlock(&dev->mt76.mutex); } @@ -777,6 +855,22 @@ static void mt7996_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + if (vif) { + struct mt7996_vif *mvif; + + mvif = (struct mt7996_vif *)vif->drv_priv; + wcid = &mvif->deflink.sta.wcid; + + if (mvif->mt76.roc_phy && + (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) { + mphy = mvif->mt76.roc_phy; + if (mphy->roc_link) + wcid = mphy->roc_link->wcid; + } else { + mphy = mt76_vif_link_phy(&mvif->deflink.mt76); + } + } + if (control->sta) { struct mt7996_sta *sta; @@ -784,11 +878,9 @@ static void mt7996_tx(struct ieee80211_hw *hw, wcid = &sta->wcid; } - if (vif && !control->sta) { - struct mt7996_vif *mvif; - - mvif = (struct mt7996_vif *)vif->drv_priv; - wcid = &mvif->deflink.sta.wcid; + if (!mphy) { + ieee80211_free_txskb(hw, skb); + return; } mt76_tx(mphy, control->sta, wcid, skb); @@ -796,12 +888,20 @@ static void mt7996_tx(struct ieee80211_hw *hw, static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int ret; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + int i, ret; - mutex_lock(&phy->dev->mt76.mutex); - ret = mt7996_mcu_set_rts_thresh(phy, val); - mutex_unlock(&phy->dev->mt76.mutex); + mutex_lock(&dev->mt76.mutex); + + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + ret = mt7996_mcu_set_rts_thresh(phy, val); + if (ret) + break; + } + + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -867,16 +967,21 @@ static int mt7996_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt76_mib_stats *mib = &phy->mib; + int i; mutex_lock(&dev->mt76.mutex); - stats->dot11RTSSuccessCount = mib->rts_cnt; - stats->dot11RTSFailureCount = mib->rts_retries_cnt; - stats->dot11FCSErrorCount = mib->fcs_err_cnt; - stats->dot11ACKFailureCount = mib->ack_fail_cnt; + memset(stats, 0, sizeof(*stats)); + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + struct mt76_mib_stats *mib = &phy->mib; + + stats->dot11RTSSuccessCount += mib->rts_cnt; + stats->dot11RTSFailureCount += mib->rts_retries_cnt; + stats->dot11FCSErrorCount += mib->fcs_err_cnt; + stats->dot11ACKFailureCount += mib->ack_fail_cnt; + } mutex_unlock(&dev->mt76.mutex); @@ -886,13 +991,16 @@ mt7996_get_stats(struct ieee80211_hw *hw, u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); union { u64 t64; u32 t32[2]; } tsf; u16 n; + if (!phy) + return 0; + lockdep_assert_held(&dev->mt76.mutex); n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 @@ -926,13 +1034,16 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; + if (!phy) + return; + mutex_lock(&dev->mt76.mutex); n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 @@ -952,13 +1063,16 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; + if (!phy) + return; + mutex_lock(&dev->mt76.mutex); n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 @@ -975,12 +1089,14 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static void mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy; mutex_lock(&dev->mt76.mutex); - phy->coverage_class = max_t(s16, coverage_class, 0); - mt7996_mac_set_coverage_class(phy); + mt7996_for_each_phy(dev, phy) { + phy->coverage_class = max_t(s16, coverage_class, 0); + mt7996_mac_set_coverage_class(phy); + } mutex_unlock(&dev->mt76.mutex); } @@ -988,33 +1104,33 @@ static int mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int max_nss = hweight8(hw->wiphy->available_antennas_tx); - u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; + int i; - if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) + if (tx_ant != rx_ant) return -EINVAL; - if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) - tx_ant = BIT(ffs(tx_ant) - 1) - 1; + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + if (!(tx_ant & phy->orig_chainmask)) + return -EINVAL; + } mutex_lock(&dev->mt76.mutex); - phy->mt76->antenna_mask = tx_ant; + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + u8 band_idx = phy->mt76->band_idx; + u8 shift = dev->chainshift[band_idx]; - /* restore to the origin chainmask which might have auxiliary path */ - if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) - phy->mt76->chainmask = ((dev->chainmask >> shift) & - (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; - else if (hweight8(tx_ant) == max_nss) - phy->mt76->chainmask = (dev->chainmask >> shift) << shift; - else - phy->mt76->chainmask = tx_ant << shift; + phy->mt76->chainmask = tx_ant & phy->orig_chainmask; + phy->mt76->antenna_mask = phy->mt76->chainmask >> shift; - mt76_set_stream_caps(phy->mt76, true); - mt7996_set_stream_vht_txbf_caps(phy); - mt7996_set_stream_he_eht_caps(phy); - mt7996_mcu_set_txpower_sku(phy); + mt76_set_stream_caps(phy->mt76, true); + mt7996_set_stream_vht_txbf_caps(phy); + mt7996_set_stream_he_eht_caps(phy); + mt7996_mcu_set_txpower_sku(phy); + } mutex_unlock(&dev->mt76.mutex); @@ -1026,7 +1142,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct station_info *sinfo) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct rate_info *txrate = &msta->wcid.rate; @@ -1060,7 +1176,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { sinfo->tx_bytes = msta->wcid.stats.tx_bytes; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); @@ -1093,9 +1209,8 @@ static void mt7996_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_link_sta *link_sta, u32 changed) { + struct mt7996_dev *dev = mt7996_hw_dev(hw); struct ieee80211_sta *sta = link_sta->sta; - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; mt7996_sta_rc_work(&changed, sta); ieee80211_queue_work(hw, &dev->rc_work); @@ -1105,9 +1220,8 @@ static int mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask) { + struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; mvif->deflink.bitrate_mask = *mask; @@ -1306,8 +1420,8 @@ void mt7996_get_et_stats(struct ieee80211_hw *hw, struct ethtool_stats *stats, u64 *data) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); struct mt76_mib_stats *mib = &phy->mib; struct mt76_ethtool_worker_info wi = { .data = data, @@ -1316,6 +1430,9 @@ void mt7996_get_et_stats(struct ieee80211_hw *hw, /* See mt7996_ampdu_stat_read_phy, etc */ int i, ei = 0; + if (!phy) + return; + mutex_lock(&dev->mt76.mutex); mt7996_mac_update_stats(phy); @@ -1409,11 +1526,18 @@ static int mt7996_set_radar_background(struct ieee80211_hw *hw, struct cfg80211_chan_def *chandef) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy; int ret = -EINVAL; bool running; + if (chandef) + phy = mt7996_band_phy(dev, chandef->chan->band); + else + phy = dev->rdd2_phy; + if (!phy) + return -EINVAL; + mutex_lock(&dev->mt76.mutex); if (dev->mt76.region == NL80211_DFS_UNSET) @@ -1464,9 +1588,14 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_vif_link *mlink = &mvif->deflink; struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mt7996_phy *phy; + + phy = mt7996_vif_link_phy(mlink); + if (!phy) + return -ENODEV; if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) wed = &dev->mt76.mmio.wed_hif2; @@ -1493,10 +1622,12 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, #endif const struct ieee80211_ops mt7996_ops = { - .add_chanctx = ieee80211_emulate_add_chanctx, - .remove_chanctx = ieee80211_emulate_remove_chanctx, - .change_chanctx = ieee80211_emulate_change_chanctx, - .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, + .add_chanctx = mt76_add_chanctx, + .remove_chanctx = mt76_remove_chanctx, + .change_chanctx = mt76_change_chanctx, + .assign_vif_chanctx = mt76_assign_vif_chanctx, + .unassign_vif_chanctx = mt76_unassign_vif_chanctx, + .switch_vif_chanctx = mt76_switch_vif_chanctx, .tx = mt7996_tx, .start = mt7996_start, .stop = mt7996_stop, @@ -1515,6 +1646,8 @@ const struct ieee80211_ops mt7996_ops = { .wake_tx_queue = mt76_wake_tx_queue, .hw_scan = mt76_hw_scan, .cancel_hw_scan = mt76_cancel_hw_scan, + .remain_on_channel = mt76_remain_on_channel, + .cancel_remain_on_channel = mt76_cancel_remain_on_channel, .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7996_channel_switch_beacon, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index ada019e44712..6abd666ff19d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2572,18 +2572,24 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, #define OFFLOAD_TX_MODE_SU BIT(0) #define OFFLOAD_TX_MODE_MU BIT(1) struct ieee80211_hw *hw = mt76_hw(dev); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &mvif->deflink.phy->mt76->chandef; - enum nl80211_band band = chandef->chan->band; + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct bss_inband_discovery_tlv *discov; struct ieee80211_tx_info *info; struct sk_buff *rskb, *skb = NULL; + struct cfg80211_chan_def *chandef; + enum nl80211_band band; struct tlv *tlv; u8 *buf, interval; int len; + if (!phy) + return -EINVAL; + + chandef = &phy->mt76->chandef; + band = chandef->chan->band; + if (vif->bss_conf.nontransmitted) return 0; @@ -4495,7 +4501,6 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) #define TX_POWER_LIMIT_TABLE_RATE 0 struct mt7996_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; - struct ieee80211_hw *hw = mphy->hw; struct tx_power_limit_table_ctrl { u8 __rsv1[4]; @@ -4515,7 +4520,7 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) struct sk_buff *skb; int i, tx_power; - tx_power = mt7996_get_power_bound(phy, hw->conf.power_level); + tx_power = mt7996_get_power_bound(phy, phy->txpower); tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &la, tx_power); mphy->txpower_cur = tx_power; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index f9aa12866a2e..d85abec19c6f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -605,6 +605,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), + .link_data_size = sizeof(struct mt7996_vif_link), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_AMSDU_OFFLOAD | MT_DRV_HW_MGMT_TXQ, @@ -622,6 +623,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, .sta_remove = mt7996_mac_sta_remove, .update_survey = mt7996_update_channel, .set_channel = mt7996_set_channel, + .vif_link_add = mt7996_vif_link_add, + .vif_link_remove = mt7996_vif_link_remove, }; struct mt7996_dev *dev; struct mt76_dev *mdev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index f1384e4e7e7f..18ae2e3ad71b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -11,6 +11,7 @@ #include "../mt76_connac.h" #include "regs.h" +#define MT7996_MAX_RADIOS 3 #define MT7996_MAX_INTERFACES 19 /* per-band */ #define MT7996_MAX_WMM_SETS 4 #define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64) @@ -270,11 +271,15 @@ struct mt7996_phy { u32 rx_ampdu_ts; u32 ampdu_ref; + int txpower; struct mt76_mib_stats mib; struct mt76_channel_state state_ts; + u16 orig_chainmask; + bool has_aux_rx; + bool counter_reset; }; struct mt7996_dev { @@ -283,6 +288,10 @@ struct mt7996_dev { struct mt76_phy mphy; }; + struct mt7996_phy *radio_phy[MT7996_MAX_RADIOS]; + struct wiphy_radio radios[MT7996_MAX_RADIOS]; + struct wiphy_radio_freq_range radio_freqs[MT7996_MAX_RADIOS]; + struct mt7996_hif *hif2; struct mt7996_reg_desc reg; u8 q_id[MT7996_MAX_QUEUE]; @@ -402,14 +411,6 @@ enum mt7996_rdd_cmd { RDD_IRQ_OFF, }; -static inline struct mt7996_phy * -mt7996_hw_phy(struct ieee80211_hw *hw) -{ - struct mt76_phy *phy = hw->priv; - - return phy->priv; -} - static inline struct mt7996_dev * mt7996_hw_dev(struct ieee80211_hw *hw) { @@ -469,12 +470,35 @@ mt7996_has_background_radar(struct mt7996_dev *dev) return true; } +static inline struct mt7996_phy * +mt7996_band_phy(struct mt7996_dev *dev, enum nl80211_band band) +{ + struct mt76_phy *mphy; + + mphy = dev->mt76.band_phys[band]; + if (!mphy) + return NULL; + + return mphy->priv; +} + static inline struct mt7996_vif_link * mt7996_vif_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, int link_id) { return (struct mt7996_vif_link *)mt76_vif_link(&dev->mt76, vif, link_id); } +static inline struct mt7996_phy * +mt7996_vif_link_phy(struct mt7996_vif_link *link) +{ + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); + + if (!mphy) + return NULL; + + return mphy->priv; +} + static inline struct mt7996_vif_link * mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) @@ -483,6 +507,10 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, link_conf); } +#define mt7996_for_each_phy(dev, phy) \ + for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \ + if (((phy) = (dev)->radio_phy[__i]) != NULL) + extern const struct ieee80211_ops mt7996_ops; extern struct pci_driver mt7996_pci_driver; extern struct pci_driver mt7996_hif_driver; @@ -494,6 +522,12 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance); u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif); int mt7996_register_device(struct mt7996_dev *dev); void mt7996_unregister_device(struct mt7996_dev *dev); +int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink); +void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink); int mt7996_eeprom_init(struct mt7996_dev *dev); int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy); int mt7996_eeprom_get_target_power(struct mt7996_dev *dev, @@ -509,7 +543,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, void mt7996_init_txpower(struct mt7996_phy *phy); int mt7996_txbf_init(struct mt7996_dev *dev); void mt7996_reset(struct mt7996_dev *dev); -int mt7996_run(struct ieee80211_hw *hw); +int mt7996_run(struct mt7996_phy *phy); int mt7996_mcu_init(struct mt7996_dev *dev); int mt7996_mcu_init_firmware(struct mt7996_dev *dev); int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev, -- 2.51.0 From e48da5c9ca293d775a1dd35fe26d44418dbc6715 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jan 2025 17:35:08 +0100 Subject: [PATCH 13/16] wifi: mt76: mt7996: fix monitor mode Enable sniffer mode via MCU command in order to properly enable promiscuous mode on the device. Link: https://patch.msgid.link/20250102163508.52945-24-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/main.c | 1 + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 21 +++++++++++++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 1 + 3 files changed, 23 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index e8a9394e5437..69dd565d8319 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -368,6 +368,7 @@ static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), MT_DMA_DCR0_RXD_G5_EN, enabled); mt7996_phy_set_rxfilter(phy); + mt7996_mcu_set_sniffer_mode(phy, enabled); } static int mt7996_add_interface(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 6abd666ff19d..58fc06a69539 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4496,6 +4496,27 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) sizeof(req), true); } +int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled) +{ + struct mt7996_dev *dev = phy->dev; + struct { + u8 band_idx; + u8 _rsv[3]; + __le16 tag; + __le16 len; + u8 enable; + u8 _pad[3]; + } __packed req = { + .band_idx = phy->mt76->band_idx, + .tag = 0, + .len = cpu_to_le16(sizeof(req) - 4), + .enable = enabled, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SNIFFER), &req, + sizeof(req), true); +} + int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) { #define TX_POWER_LIMIT_TABLE_RATE 0 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 18ae2e3ad71b..1cfcac51a338 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -621,6 +621,7 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); void mt7996_mcu_exit(struct mt7996_dev *dev); int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); +int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { -- 2.51.0 From dd1649ef966bb87053c17385ea2cfd1758f5385b Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 9 Jan 2025 19:04:35 +0800 Subject: [PATCH 14/16] wifi: mt76: mt7915: fix register mapping Bypass the entry when ofs is equal to dev->reg.map[i].size. Without this patch, it would get incorrect register mapping when the CR address is located at the boundary of an entry. Fixes: cd4c314a65d3 ("mt76: mt7915: refine register definition") Signed-off-by: Peter Chiu Signed-off-by: Shengyu Qu Link: https://patch.msgid.link/OSZPR01MB843401EAA1DA6BD7AEF356F298132@OSZPR01MB8434.jpnprd01.prod.outlook.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 530182e20ce2..876f0692850a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -486,7 +486,7 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) continue; ofs = addr - dev->reg.map[i].phys; - if (ofs > dev->reg.map[i].size) + if (ofs >= dev->reg.map[i].size) continue; return dev->reg.map[i].maps + ofs; -- 2.51.0 From d07ecb4f7070e84de49e8fa4e5a83dd52716d805 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 9 Jan 2025 19:04:36 +0800 Subject: [PATCH 15/16] wifi: mt76: mt7996: fix register mapping Bypass the entry when ofs is equal to dev->reg.map[i].size. Without this patch, it would get incorrect register mapping when the CR address is located at the boundary of an entry. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: Peter Chiu Signed-off-by: Shengyu Qu Link: https://patch.msgid.link/OSZPR01MB84344FEFF53004B5CF40BCC198132@OSZPR01MB8434.jpnprd01.prod.outlook.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index d85abec19c6f..7a8ee6c75cf2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -177,7 +177,7 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) continue; ofs = addr - dev->reg.map[i].phys; - if (ofs > dev->reg.map[i].size) + if (ofs >= dev->reg.map[i].size) continue; return dev->reg.map[i].mapped + ofs; -- 2.51.0 From 1b97fc8443aea01922560de9f24a6383e6eb6ae8 Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 3 Jan 2025 21:35:59 +0800 Subject: [PATCH 16/16] wifi: mt76: mt7925: fix the unfinished command of regd_notifier before suspend Before entering suspend, we need to ensure that all MCU command are completed. In some cases, such as with regd_notifier, there is a chance that CLC commands, will be executed before suspend. Signed-off-by: Quan Zhou Link: https://patch.msgid.link/3af7b4e5bf7437832b016e32743657d1d55b1f9d.1735910288.git.quan.zhou@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/init.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index ddc654b9ea5e..34b6adc5ea0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -79,11 +79,14 @@ mt7925_regd_notifier(struct wiphy *wiphy, mdev->region = req->dfs_region; dev->country_ie_env = req->country_ie_env; + dev->regd_in_progress = true; mt792x_mutex_acquire(dev); mt7925_mcu_set_clc(dev, req->alpha2, req->country_ie_env); mt7925_mcu_set_channel_domain(hw->priv); mt7925_set_tx_sar_pwr(hw, NULL); mt792x_mutex_release(dev); + dev->regd_in_progress = false; + wake_up(&dev->wait); } static void mt7925_mac_init_basic_rates(struct mt792x_dev *dev) @@ -226,6 +229,7 @@ int mt7925_register_device(struct mt792x_dev *dev) spin_lock_init(&dev->pm.wake.lock); mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); + init_waitqueue_head(&dev->wait); spin_lock_init(&dev->pm.txq_lock); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt792x_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7925_scan_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 9aec675450f2..4986aaccc753 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -455,6 +455,9 @@ static int mt7925_pci_suspend(struct device *device) if (err < 0) goto restore_suspend; + wait_event_timeout(dev->wait, + !dev->regd_in_progress, 5 * HZ); + /* always enable deep sleep during suspend to reduce * power consumption */ -- 2.51.0