[PATCH 17/18] wifi: mt76: mt7925: fix MT7927 band_idx for stable 5GHz/6GHz operation
Javier Tia
floss at jetm.me
Fri Mar 6 16:33:36 PST 2026
The MT7927 (Filogic 380) firmware requires explicit band_idx assignment
(0 for 2.4GHz, 1 for 5GHz/6GHz) instead of 0xff (auto-select) used by
MT7925. Without this, the firmware selects the wrong radio for 5GHz and
6GHz connections, causing WPA 4-way handshake timeout and data plane
failures on those bands.
Add mt7925_mt7927_hw_band_from_nl() helper to map nl80211_band to
hardware band index, and use it throughout the driver:
- mac_link_bss_add: set band_idx from link channel at BSS creation
- assign_vif_chanctx: update band_idx when channel context changes,
resend DEV_INFO to firmware if band changed
- bss_basic_tlv: set band_idx in BSS info sent to firmware
- set_roc / set_mlo_roc / abort_roc: send concrete dbdcband instead
of 0xff auto-select
- roc_iter / roc_handle_grant: clamp invalid grant band_idx values
using rfband as fallback, process grants for all MT7927 request
types (not just JOIN)
All changes guarded by is_mt7927() - no impact on MT7925 behavior.
Originally discovered and fixed by marcin-fm; Loong0x00 contributed
additional improvements based on marcin-fm's patch.
Co-developed-by: Marcin FM <marcin at lgic.pl>
Signed-off-by: Marcin FM <marcin at lgic.pl>
Co-developed-by: 张旭涵 <Loong.0x00 at gmail.com>
Signed-off-by: 张旭涵 <Loong.0x00 at gmail.com>
Assisted-by: Claude Code <noreply at anthropic.com> (claude-opus-4-6)
Tested-by: Marcin FM <marcin at lgic.pl>
Tested-by: Cristian-Florin Radoi <radoi.chris at gmail.com>
Tested-by: George Salukvadze <giosal90 at gmail.com>
Tested-by: Evgeny Kapusta <3193631 at gmail.com>
Tested-by: Samu Toljamo <samu.toljamo at gmail.com>
Tested-by: Ariel Rosenfeld <ariel.rosenfeld.750 at gmail.com>
Tested-by: Chapuis Dario <chapuisdario4 at gmail.com>
Tested-by: Thibaut François <tibo at humeurlibre.fr>
Tested-by: 张旭涵 <Loong.0x00 at gmail.com>
Signed-off-by: Javier Tia <floss at jetm.me>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 40 +++++++++++++++-
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 54 ++++++++++++++++++----
drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 5 ++
3 files changed, 87 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index f82c56c46324..fcb9f26c8b87 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -400,7 +400,24 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev,
mconf->mt76.omac_idx = ieee80211_vif_is_mld(vif) ?
0 : mconf->mt76.idx;
- mconf->mt76.band_idx = 0xff;
+
+ if (is_mt7927(&dev->mt76)) {
+ struct ieee80211_channel *chan = NULL;
+
+ if (link_conf->chanreq.oper.chan)
+ chan = link_conf->chanreq.oper.chan;
+ else if (mvif->phy->mt76->chandef.chan)
+ chan = mvif->phy->mt76->chandef.chan;
+
+ if (chan)
+ mconf->mt76.band_idx =
+ mt7925_mt7927_hw_band_from_nl(chan->band);
+ else
+ mconf->mt76.band_idx = 0xff;
+ } else {
+ mconf->mt76.band_idx = 0xff;
+ }
+
mconf->mt76.wmm_idx = ieee80211_vif_is_mld(vif) ?
0 : mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS;
mconf->mt76.link_idx = hweight16(mvif->valid_links);
@@ -417,7 +434,8 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev,
mlink->wcid.idx = idx;
mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
- mt76_wcid_init(&mlink->wcid, 0);
+ mt76_wcid_init(&mlink->wcid,
+ mconf->mt76.band_idx == 0xff ? 0 : mconf->mt76.band_idx);
mt7925_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -2119,9 +2137,12 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
{
struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv;
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_link_sta *mlink;
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct ieee80211_bss_conf *pri_link_conf;
struct mt792x_bss_conf *mconf;
+ u8 band_idx;
+ u8 old_band;
mutex_lock(&dev->mt76.mutex);
@@ -2137,6 +2158,21 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
mconf = &mvif->bss_conf;
}
+ old_band = mconf->mt76.band_idx;
+ if (is_mt7927(&dev->mt76) && ctx->def.chan) {
+ band_idx = mt7925_mt7927_hw_band_from_nl(ctx->def.chan->band);
+ mconf->mt76.band_idx = band_idx;
+ mlink = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
+ if (mlink)
+ mlink->wcid.phy_idx = band_idx;
+
+ if (old_band != band_idx && vif->type == NL80211_IFTYPE_STATION &&
+ mlink)
+ mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf,
+ &mconf->mt76, &mlink->wcid,
+ true);
+ }
+
mconf->mt76.ctx = ctx;
mctx->bss_conf = mconf;
mutex_unlock(&dev->mt76.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 8b5ffb240d52..3458aa8c79cb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -301,16 +301,36 @@ mt7925_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb)
static void
mt7925_mcu_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
- struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt7925_roc_grant_tlv *grant = priv;
+ u8 band_idx = grant->dbdcband;
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION)
return;
- if (mvif->idx != grant->bss_idx)
+ if (mvif->bss_conf.mt76.idx != grant->bss_idx)
return;
- mvif->band_idx = grant->dbdcband;
+ /* MT7927 firmware requires band_idx 0 (2.4G) or 1 (5/6G).
+ * Clamp invalid grant values using rfband as fallback.
+ */
+ if (is_mt7927(&mvif->phy->dev->mt76) && band_idx > 1) {
+ switch (grant->rfband) {
+ case 1: /* 2.4 GHz */
+ band_idx = 0;
+ break;
+ case 2: /* 5 GHz */
+ case 3: /* 6 GHz */
+ band_idx = 1;
+ break;
+ default:
+ band_idx = mvif->bss_conf.mt76.band_idx <= 1 ?
+ mvif->bss_conf.mt76.band_idx : 0;
+ break;
+ }
+ }
+
+ mvif->bss_conf.mt76.band_idx = band_idx;
}
static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev,
@@ -327,10 +347,11 @@ static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev,
if (grant->reqtype == MT7925_ROC_REQ_ROC)
ieee80211_ready_on_channel(hw);
- else if (grant->reqtype == MT7925_ROC_REQ_JOIN)
+ else if (is_mt7927(&dev->mt76) || grant->reqtype == MT7925_ROC_REQ_JOIN)
ieee80211_iterate_active_interfaces_atomic(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_mcu_roc_iter, grant);
+
dev->phy.roc_grant = true;
wake_up(&dev->phy.roc_wait);
duration = le32_to_cpu(grant->max_interval);
@@ -1378,10 +1399,15 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
req.roc[i].center_chan2 = 0;
req.roc[i].center_chan2_from_ap = 0;
- /* STR : 0xfe indicates BAND_ALL with enabling DBDC
- * EMLSR : 0xff indicates (BAND_AUTO) without DBDC
- */
- req.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ? 0xfe : 0xff;
+ if (is_mt7927(&mvif->phy->dev->mt76))
+ req.roc[i].dbdcband =
+ mt7925_mt7927_hw_band_from_nl(chan->band);
+ else
+ /* STR : 0xfe indicates BAND_ALL with enabling DBDC
+ * EMLSR : 0xff indicates (BAND_AUTO) without DBDC
+ */
+ req.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ?
+ 0xfe : 0xff;
if (chan->hw_value < center_ch)
req.roc[i].sco = 1; /* SCA */
@@ -1419,7 +1445,9 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
.bw_from_ap = CMD_CBW_20MHZ,
.center_chan = center_ch,
.center_chan_from_ap = center_ch,
- .dbdcband = 0xff, /* auto */
+ .dbdcband = is_mt7927(&dev->mt76) ?
+ mt7925_mt7927_hw_band_from_nl(chan->band) :
+ 0xff, /* auto */
},
};
@@ -1466,7 +1494,10 @@ int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
.len = cpu_to_le16(sizeof(struct roc_abort_tlv)),
.tokenid = token_id,
.bss_idx = mconf->mt76.idx,
- .dbdcband = 0xff, /* auto*/
+ .dbdcband = is_mt7927(&dev->mt76) &&
+ mconf->mt76.band_idx <= 1 ?
+ mconf->mt76.band_idx :
+ 0xff, /* auto */
},
};
@@ -2495,6 +2526,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band,
link_sta);
+ if (is_mt7927(phy->dev))
+ mconf->mt76.band_idx = mt7925_mt7927_hw_band_from_nl(band);
+
if (band == NL80211_BAND_2GHZ)
basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX);
else
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index ba3d2c4de4ce..d3c89ea0afab 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -63,6 +63,11 @@ enum mt7925_roc_req {
MT7925_ROC_REQ_NUM
};
+static inline u8 mt7925_mt7927_hw_band_from_nl(enum nl80211_band band)
+{
+ return band == NL80211_BAND_2GHZ ? 0 : 1;
+}
+
enum {
UNI_EVENT_ROC_GRANT = 0,
UNI_EVENT_ROC_GRANT_SUB_LINK = 4,
--
2.53.0
More information about the Linux-mediatek
mailing list