[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260120062854.126501-10-zac@zacbowling.com>
Date: Mon, 19 Jan 2026 22:28:52 -0800
From: Zac <zac@...bowling.com>
To: sean.wang@...nel.org
Cc: deren.wu@...iatek.com,
kvalo@...nel.org,
linux-kernel@...r.kernel.org,
linux-mediatek@...ts.infradead.org,
linux-wireless@...r.kernel.org,
lorenzo@...nel.org,
nbd@....name,
ryder.lee@...iatek.com,
sean.wang@...iatek.com,
stable@...r.kernel.org,
linux@...me.work,
zbowling@...il.com,
Zac Bowling <zac@...bowling.com>
Subject: [PATCH 09/11] wifi: mt76: mt7925: fix MLO roaming and ROC setup issues
From: Zac Bowling <zac@...bowling.com>
Fix two issues related to MLO roaming and remain-on-channel operations:
1. Key removal failure during MLO roaming:
During MLO roaming, key removal can fail because the WCID (wireless client
ID) is already cleaned up before the key removal operation completes.
When roaming between APs in an MLO setup:
- mac80211 triggers sta_state changes
- mt7925_mac_link_sta_remove() is called for the old link
- WCID is cleared via mt76_wcid_cleanup()
- Later, key removal MCU command uses the now-invalid WCID
Fix by checking if the WCID is still valid before sending key removal
commands to firmware. If the WCID has already been cleaned up, skip
the MCU command since the firmware has already removed the keys.
2. Kernel warning in MLO ROC setup:
When starting a remain-on-channel operation in MLO mode, the driver
passes incorrect parameters to mt7925_mcu_set_roc(), causing a kernel
warning about invalid chanctx usage.
Fix by checking for valid chanctx and link configuration before
setting up ROC, and use the correct link_id from the vif when
available.
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@...bowling.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 9 ++++++++-
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 20 +++++++++++++------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 5f8a28d5ff72..81373e479abd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -605,8 +605,15 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
mconf = mt792x_vif_to_link(mvif, link_id);
mlink = mt792x_sta_to_link(msta, link_id);
- if (!link_conf || !mconf || !mlink)
+ if (!link_conf || !mconf || !mlink) {
+ /* During MLO roaming, link state may be torn down before
+ * mac80211 requests key removal. If removing a key and
+ * the link is already gone, consider it successfully removed.
+ */
+ if (cmd != SET_KEY)
+ return 0;
return -EINVAL;
+ }
wcid = &mlink->wcid;
wcid_keyidx = &wcid->hw_key_idx;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 1c58b0be2be4..6f7fc1b9a440 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1342,15 +1342,23 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
for (i = 0; i < ARRAY_SIZE(links); i++) {
links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) :
mconf->link_id;
+
link_conf = mt792x_vif_to_bss_conf(vif, links[i].id);
- if (WARN_ON_ONCE(!link_conf))
- return -EPERM;
+ if (!link_conf)
+ return -ENOLINK;
links[i].chan = link_conf->chanreq.oper.chan;
- if (WARN_ON_ONCE(!links[i].chan))
- return -EPERM;
+ if (!links[i].chan)
+ /* Channel not configured yet - this can happen during
+ * MLO AP setup when links are being added sequentially.
+ * Return -ENOLINK to indicate link not ready.
+ */
+ return -ENOLINK;
links[i].mconf = mt792x_vif_to_link(mvif, links[i].id);
+ if (!links[i].mconf)
+ return -ENOLINK;
+
links[i].tag = links[i].id == mconf->link_id ?
UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK;
@@ -1364,8 +1372,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
type = MT7925_ROC_REQ_JOIN;
for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) {
- if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan))
- continue;
+ if (!links[i].mconf || !links[i].chan)
+ return -ENOLINK;
chan = links[i].chan;
center_ch = ieee80211_frequency_to_channel(chan->center_freq);
--
2.52.0
Powered by blists - more mailing lists