* [PATCH 00/19] wifi: mt76: mt7925: fix up MLO link lifetime and error handling
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
From: Sean Wang <sean.wang@mediatek.com>
Hi,
This series fix up MLO link STA lifetime and error handling in mt7925.
The current add path may expose partially initialized links and does
not reliably release host resources when firmware commands fail (e.g.
MCU timeouts). In addition, several helpers internally look up mlink,
creating implicit dependencies on driver state and making the code
harder to reason about and maintain.
Switch link STA handling to RCU lifetime, align WCID publish/teardown
ordering, pass mlink explicitly to helpers, and add host-side unwind
logic to release resources when link add fails.
Sean
Sean Wang (19):
wifi: mt76: mt7925: pass mlink to sta_amsdu_tlv()
wifi: mt76: mt7925: pass WCID indices to bss_basic_tlv()
wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()
wifi: mt76: mt7925: pass mlink to mcu_sta_update()
wifi: mt76: mt7925: resolve primary mlink via def_wcid
wifi: mt76: mt7925: pass mlink to mac_link_sta_remove()
wifi: mt76: mt7925: pass mlink to sta_hdr_trans_tlv()
wifi: mt76: mt7925: validate mlink in sta_hdr_trans_tlv()
wifi: mt76: mt7925: pass mlink to wtbl_update_hdr_trans()
wifi: mt76: mt7925: pass mlink to set_link_key()
wifi: mt76: mt7925: resolve link after acquiring mt76 mutex
wifi: mt76: mt7925: pass mconf and mlink to wtbl_update_hdr_trans()
wifi: mt76: mt7925: make WCID cleanup unconditional in
sta_remove_links()
wifi: mt76: mt7925: unwind WCID setup on link STA add failure
wifi: mt76: mt7925: drop WCID reinit after publish
wifi: mt76: mt7925: move WCID teardown into link_sta_remove()
wifi: mt76: mt7925: switch link STA allocation to RCU lifetime
wifi: mt76: mt7925: publish msta->link after successful link add
wifi: mt76: mt7925: host-only unwind published links on add failure
.../net/wireless/mediatek/mt76/mt7925/mac.c | 3 +-
.../net/wireless/mediatek/mt76/mt7925/main.c | 221 +++++++++++++-----
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 180 +++++++-------
.../net/wireless/mediatek/mt76/mt7925/mcu.h | 7 +
.../wireless/mediatek/mt76/mt7925/mt7925.h | 8 +-
drivers/net/wireless/mediatek/mt76/mt792x.h | 1 +
6 files changed, 280 insertions(+), 140 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH 01/19] wifi: mt76: mt7925: pass mlink to sta_amsdu_tlv()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mcu_sta_amsdu_tlv() and
pass mlink from the caller instead. The link context is already known
so the lookup is redundant.
This makes link ownership explicit and keeps the helper lookup-free.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index abcdd0e0b3b5..fa5f79004a6e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1726,10 +1726,9 @@ mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)
static void
mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
- struct ieee80211_link_sta *link_sta)
+ struct ieee80211_link_sta *link_sta,
+ struct mt792x_link_sta *mlink)
{
- struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
- struct mt792x_link_sta *mlink;
struct sta_rec_amsdu *amsdu;
struct tlv *tlv;
@@ -1745,7 +1744,6 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,
amsdu->max_amsdu_num = 8;
amsdu->amsdu_en = true;
- mlink = mt792x_sta_to_link(msta, link_sta->link_id);
mlink->wcid.amsdu = true;
switch (link_sta->agg.max_amsdu_len) {
@@ -1966,6 +1964,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv;
struct mt76_dev *dev = phy->dev;
struct mt792x_bss_conf *mconf;
+ struct mt792x_link_sta *mlink;
struct sk_buff *skb;
int conn_state;
@@ -1980,6 +1979,8 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
CONN_STATE_DISCONNECT;
if (info->enable && info->link_sta) {
+ mlink = container_of(info->wcid, struct mt792x_link_sta, wcid);
+
mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf,
info->link_sta,
conn_state, info->newly);
@@ -1987,7 +1988,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
mt7925_mcu_sta_ht_tlv(skb, info->link_sta);
mt7925_mcu_sta_vht_tlv(skb, info->link_sta);
mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta);
- mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta);
+ mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta, mlink);
mt7925_mcu_sta_he_tlv(skb, info->link_sta);
mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta);
mt7925_mcu_sta_eht_tlv(skb, info->link_sta);
--
2.43.0
^ permalink raw reply related
* [PATCH 02/19] wifi: mt76: mt7925: pass WCID indices to bss_basic_tlv()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mcu_bss_basic_tlv() and
pass the resolved WCID indices from the caller instead. The link
context is already known, so the lookup is redundant.
This makes link ownership explicit and keeps the helper lookup-free.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 34 +++++++---
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 68 ++++++++++++-------
.../net/wireless/mediatek/mt76/mt7925/mcu.h | 7 ++
3 files changed, 73 insertions(+), 36 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index afcc0fa4aa35..353461f0e169 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -850,20 +850,22 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
struct ieee80211_vif *vif,
- struct ieee80211_link_sta *link_sta)
+ struct ieee80211_link_sta *link_sta,
+ struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct ieee80211_bss_conf *link_conf;
struct mt792x_bss_conf *mconf;
u8 link_id = link_sta->link_id;
- struct mt792x_link_sta *mlink;
struct mt792x_sta *msta;
struct mt76_wcid *wcid;
int ret, idx;
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
- mlink = mt792x_sta_to_link(msta, link_id);
+
+ if (WARN_ON_ONCE(!mlink))
+ return -EINVAL;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
@@ -898,12 +900,21 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
- if (ieee80211_vif_is_mld(vif))
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, link_sta != mlink->pri_link);
- else
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, false);
+ struct mt792x_link_sta *mlink_bc;
+
+ mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
+
+ if (ieee80211_vif_is_mld(vif)) {
+ mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta,
+ mlink_bc->wcid.idx, mlink->wcid.idx,
+ link_sta != mlink->pri_link);
+ } else {
+ mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta,
+ mlink_bc->wcid.idx, mlink->wcid.idx,
+ false);
+ }
}
if (ieee80211_vif_is_mld(vif) &&
@@ -965,7 +976,7 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
mlink->wcid.def_wcid = &msta->deflink.wcid;
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
- mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta);
+ mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta, mlink);
}
return err;
@@ -989,7 +1000,8 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links);
} else {
- err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink);
+ err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink,
+ &msta->deflink);
}
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index fa5f79004a6e..0d5519e5dc4a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -2476,7 +2476,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
struct ieee80211_chanctx_conf *ctx,
- struct mt76_phy *phy, u16 wlan_idx,
+ struct mt76_phy *phy,
+ u16 bmc_tx_wlan_idx,
+ u16 sta_wlan_idx,
bool enable)
{
struct ieee80211_vif *vif = link_conf->vif;
@@ -2485,7 +2487,6 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
&link_conf->chanreq.oper;
enum nl80211_band band = chandef->chan->band;
struct mt76_connac_bss_basic_tlv *basic_req;
- struct mt792x_link_sta *mlink;
struct tlv *tlv;
int conn_type;
u8 idx;
@@ -2509,20 +2510,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta);
basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int);
basic_req->dtim_period = link_conf->dtim_period;
- basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
+ basic_req->bmc_tx_wlan_idx = cpu_to_le16(bmc_tx_wlan_idx);
basic_req->link_idx = mconf->mt76.idx;
-
- if (link_sta) {
- struct mt792x_sta *msta;
-
- msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
- mlink = mt792x_sta_to_link(msta, link_sta->link_id);
-
- } else {
- mlink = &mconf->vif->sta.deflink;
- }
-
- basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx);
+ basic_req->sta_idx = cpu_to_le16(sta_wlan_idx);
basic_req->omac_idx = mconf->mt76.omac_idx;
basic_req->band_idx = mconf->mt76.band_idx;
basic_req->wmm_idx = mconf->mt76.wmm_idx;
@@ -2829,16 +2819,16 @@ void mt7925_mcu_del_dev(struct mt76_dev *mdev,
&dev_req, sizeof(dev_req), true);
}
-int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
- struct ieee80211_chanctx_conf *ctx,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_link_sta *link_sta,
- int enable)
+int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,
+ struct ieee80211_chanctx_conf *ctx,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
+ u16 bmc_tx_wlan_idx,
+ u16 sta_wlan_idx,
+ int enable)
{
- struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;
struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);
struct mt792x_dev *dev = phy->dev;
- struct mt792x_link_sta *mlink_bc;
struct sk_buff *skb;
skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
@@ -2846,11 +2836,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
if (IS_ERR(skb))
return PTR_ERR(skb);
- mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
-
/* bss_basic must be first */
mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76,
- mlink_bc->wcid.idx, enable);
+ bmc_tx_wlan_idx, sta_wlan_idx, enable);
mt7925_mcu_bss_sec_tlv(skb, link_conf);
mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf);
mt7925_mcu_bss_qos_tlv(skb, link_conf);
@@ -2871,6 +2859,36 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
MCU_UNI_CMD(BSS_INFO_UPDATE), true);
}
+int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
+ struct ieee80211_chanctx_conf *ctx,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
+ int enable)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;
+ struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);
+ struct mt792x_link_sta *mlink_bc;
+ struct mt792x_link_sta *mlink;
+ u16 sta_wlan_idx;
+
+ sta_wlan_idx = mvif->sta.deflink.wcid.idx;
+
+ mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
+
+ if (link_sta) {
+ struct mt792x_sta *msta = (void *)link_sta->sta->drv_priv;
+
+ mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (WARN_ON(!mlink))
+ return -1;
+ } else {
+ mlink = &mconf->vif->sta.deflink;
+ }
+
+ return mt7925_mcu_add_bss_info_sta(phy, ctx, link_conf, link_sta,
+ mlink_bc->wcid.idx, mlink->wcid.idx, enable);
+}
+
int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)
{
struct mt76_dev *mdev = phy->dev;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
index e09e0600534a..56e2772f3ffe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
@@ -693,6 +693,13 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
int enable);
+int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,
+ struct ieee80211_chanctx_conf *ctx,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
+ u16 bmc_tx_wlan_idx,
+ u16 sta_wlan_idx,
+ int enable);
int mt7925_mcu_set_timing(struct mt792x_phy *phy,
struct ieee80211_bss_conf *link_conf);
int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable);
--
2.43.0
^ permalink raw reply related
* [PATCH 03/19] wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mcu_sta_mld_tlv() and
pass mlink and mconf from the caller instead. The link context is
already known at the call site, making the lookup redundant.
This keeps the helper lookup-free and makes MLD link selection
explicit.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 53 +++++++++++++------
1 file changed, 36 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 0d5519e5dc4a..7582a8c48607 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1914,36 +1914,53 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,
static void
mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct mt792x_bss_conf *mconf,
+ struct mt792x_link_sta *mlink)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
- unsigned long valid = mvif->valid_links;
- struct mt792x_bss_conf *mconf;
- struct mt792x_link_sta *mlink;
+ struct mt792x_dev *dev = mvif->phy->dev;
+ struct mt792x_bss_conf *mconf_pri;
struct sta_rec_mld *mld;
struct tlv *tlv;
- int i, cnt = 0;
+ u8 cnt = 0;
+
+ /* Primary link always uses driver's deflink WCID. */
+ mconf_pri = (msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) ?
+ mt792x_vif_to_link(mvif, msta->deflink_id) : NULL;
+
+ /* If caller is operating on deflink, reuse its mconf as primary. */
+ if (!mconf_pri && mlink == &msta->deflink)
+ mconf_pri = mconf;
+
+ if (!mconf_pri) {
+ dev_warn_ratelimited(dev->mt76.dev,
+ "mt7925: MLD_TLV_LINK skip (no primary mconf) sta=%pM\n",
+ sta->addr);
+ return;
+ }
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld));
mld = (struct sta_rec_mld *)tlv;
memcpy(mld->mac_addr, sta->addr, ETH_ALEN);
+
mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx);
mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
- mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2);
- for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
- if (cnt == mld->link_num)
- break;
+ /* Always encode primary link first. */
+ mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
+ mld->link[cnt++].bss_idx = mconf_pri->mt76.idx;
- mconf = mt792x_vif_to_link(mvif, i);
- mlink = mt792x_sta_to_link(msta, i);
+ /* Optionally encode the currently-updated secondary link. */
+ if (mlink && mlink != &msta->deflink && mconf) {
+ mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt++].bss_idx = mconf->mt76.idx;
-
- if (mlink != &msta->deflink)
- mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
}
+
+ mld->link_num = cnt;
}
static void
@@ -1969,6 +1986,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
int conn_state;
mconf = mt792x_vif_to_link(mvif, info->wcid->link_id);
+ mlink = container_of(info->wcid, struct mt792x_link_sta, wcid);
skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid,
MT7925_STA_UPDATE_MAX_SIZE);
@@ -1979,8 +1997,6 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
CONN_STATE_DISCONNECT;
if (info->enable && info->link_sta) {
- mlink = container_of(info->wcid, struct mt792x_link_sta, wcid);
-
mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf,
info->link_sta,
conn_state, info->newly);
@@ -1999,7 +2015,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
info->state);
if (info->state != MT76_STA_INFO_STATE_NONE) {
- mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta);
+ mt7925_mcu_sta_mld_tlv(skb, info->vif,
+ info->link_sta->sta,
+ mconf, mlink);
+
mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta);
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH 04/19] wifi: mt76: mt7925: pass mlink to mcu_sta_update()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mcu_sta_update() and
pass the resolved mlink from the caller instead. The link context is
already known at the call site, making the lookup redundant.
This keeps the helper lookup-free and makes WCID selection explicit.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/mac.c | 3 ++-
.../net/wireless/mediatek/mt76/mt7925/main.c | 27 +++++++++++++------
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 12 +++------
.../wireless/mediatek/mt76/mt7925/mt7925.h | 4 ++-
4 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 82eedd80f694..139c2a7871fc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1285,7 +1285,8 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
if (vif->type == NL80211_IFTYPE_AP) {
mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid,
true, NULL);
- mt7925_mcu_sta_update(dev, NULL, vif, true,
+ mt7925_mcu_sta_update(dev, NULL, vif,
+ &mvif->sta.deflink, true,
MT76_STA_INFO_STATE_NONE);
mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 353461f0e169..c65e32a14c01 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -919,23 +919,31 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
if (ieee80211_vif_is_mld(vif) &&
link_sta == mlink->pri_link) {
- ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
+ ret = mt7925_mcu_sta_update(dev, link_sta, vif,
+ mlink, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
return ret;
} else if (ieee80211_vif_is_mld(vif) &&
link_sta != mlink->pri_link) {
+ struct mt792x_link_sta *pri_mlink;
+
+ pri_mlink = mt792x_sta_to_link(msta, mlink->pri_link->link_id);
+
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
- true, MT76_STA_INFO_STATE_ASSOC);
+ pri_mlink, true,
+ MT76_STA_INFO_STATE_ASSOC);
if (ret)
return ret;
- ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
+ ret = mt7925_mcu_sta_update(dev, link_sta, vif,
+ mlink, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
return ret;
} else {
- ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
+ ret = mt7925_mcu_sta_update(dev, link_sta, vif,
+ mlink, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
return ret;
@@ -1075,7 +1083,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));
- mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_ASSOC);
+ mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true,
+ MT76_STA_INFO_STATE_ASSOC);
mt792x_mutex_release(dev);
}
@@ -1119,7 +1128,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid);
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
- mt7925_mcu_sta_update(dev, link_sta, vif, false,
+ mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false,
MT76_STA_INFO_STATE_NONE);
mt7925_mac_wtbl_update(dev, mlink->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -1744,7 +1753,8 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (err)
goto out;
- err = mt7925_mcu_sta_update(dev, NULL, vif, true,
+ err = mt7925_mcu_sta_update(dev, NULL, vif,
+ &mvif->sta.deflink, true,
MT76_STA_INFO_STATE_NONE);
out:
mt792x_mutex_release(dev);
@@ -1887,7 +1897,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
mt792x_mutex_acquire(dev);
if (changed & BSS_CHANGED_ASSOC) {
- mt7925_mcu_sta_update(dev, NULL, vif, true,
+ mt7925_mcu_sta_update(dev, NULL, vif,
+ &mvif->sta.deflink, true,
MT76_STA_INFO_STATE_ASSOC);
mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 7582a8c48607..fa4915b65fcc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -2036,7 +2036,9 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct ieee80211_link_sta *link_sta,
- struct ieee80211_vif *vif, bool enable,
+ struct ieee80211_vif *vif,
+ struct mt792x_link_sta *mlink,
+ bool enable,
enum mt76_sta_info_state state)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
@@ -2051,14 +2053,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
.offload_fw = true,
.rcpi = to_rcpi(rssi),
};
- struct mt792x_sta *msta;
- struct mt792x_link_sta *mlink;
- if (link_sta) {
- msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
- mlink = mt792x_sta_to_link(msta, link_sta->link_id);
- }
- info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid;
+ info.wcid = &mlink->wcid;
info.newly = state != MT76_STA_INFO_STATE_ASSOC;
return mt7925_mcu_sta_cmd(&dev->mphy, &info);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 0f0eff748bb7..95f29dae4d9d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -250,7 +250,9 @@ int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev,
bool enable);
int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct ieee80211_link_sta *link_sta,
- struct ieee80211_vif *vif, bool enable,
+ struct ieee80211_vif *vif,
+ struct mt792x_link_sta *mlink,
+ bool enable,
enum mt76_sta_info_state state);
int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag);
int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf);
--
2.43.0
^ permalink raw reply related
* [PATCH 05/19] wifi: mt76: mt7925: resolve primary mlink via def_wcid
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Use mlink->wcid.def_wcid to obtain the primary mlink in
mt7925_mac_link_sta_add() instead of calling mt792x_sta_to_link().
The primary link context is already carried by the WCID, so the extra
lookup is redundant. This makes the add path follow the existing WCID
association directly.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index c65e32a14c01..d7a09a0a79fb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -927,8 +927,17 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
} else if (ieee80211_vif_is_mld(vif) &&
link_sta != mlink->pri_link) {
struct mt792x_link_sta *pri_mlink;
+ struct mt76_wcid *pri_wcid;
- pri_mlink = mt792x_sta_to_link(msta, mlink->pri_link->link_id);
+ /* alternative lookup via def_wcid */
+ pri_wcid = mlink->wcid.def_wcid;
+
+ pri_mlink = pri_wcid ?
+ container_of(pri_wcid, struct mt792x_link_sta, wcid) :
+ NULL;
+
+ if (WARN_ON_ONCE(!pri_mlink))
+ return -EINVAL;
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
pri_mlink, true,
--
2.43.0
^ permalink raw reply related
* [PATCH 06/19] wifi: mt76: mt7925: pass mlink to mac_link_sta_remove()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mac_link_sta_remove()
and pass mlink from mt7925_mac_sta_remove_links() instead. The link is
already resolved there, making the extra lookup redundant.
This keeps the remove helper lookup-free and avoids hidden dependence on
msta->link[link_id] during teardown.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index d7a09a0a79fb..ddff6c5ab876 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1121,16 +1121,12 @@ EXPORT_SYMBOL_GPL(mt7925_mac_sta_event);
static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
struct ieee80211_vif *vif,
- struct ieee80211_link_sta *link_sta)
+ struct ieee80211_link_sta *link_sta,
+ struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct ieee80211_bss_conf *link_conf;
u8 link_id = link_sta->link_id;
- struct mt792x_link_sta *mlink;
- struct mt792x_sta *msta;
-
- msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
- mlink = mt792x_sta_to_link(msta, link_id);
mt7925_roc_abort_sync(dev);
@@ -1213,7 +1209,7 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
if (!mlink)
continue;
- mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta);
+ mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink);
wcid = &mlink->wcid;
rcu_assign_pointer(msta->link[link_id], NULL);
--
2.43.0
^ permalink raw reply related
* [PATCH 07/19] wifi: mt76: mt7925: pass mlink to sta_hdr_trans_tlv()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mcu_sta_hdr_trans_tlv()
and pass the resolved mlink from the caller instead. The link is
already known at the call site, making the lookup redundant.
This keeps the helper lookup-free and makes WCID selection explicit.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 24 +++++++++----------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index fa4915b65fcc..c474dd358650 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1066,9 +1066,9 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware);
static void
mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
- struct ieee80211_link_sta *link_sta)
+ struct ieee80211_link_sta *link_sta,
+ struct mt792x_link_sta *mlink)
{
- struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct sta_rec_hdr_trans *hdr_trans;
struct mt76_wcid *wcid;
struct tlv *tlv;
@@ -1082,15 +1082,7 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
else
hdr_trans->from_ds = true;
- if (link_sta) {
- struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
- struct mt792x_link_sta *mlink;
-
- mlink = mt792x_sta_to_link(msta, link_sta->link_id);
- wcid = &mlink->wcid;
- } else {
- wcid = &mvif->sta.deflink.wcid;
- }
+ wcid = &mlink->wcid;
if (!wcid)
return;
@@ -1127,7 +1119,10 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
return PTR_ERR(skb);
/* starec hdr trans */
- mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta);
+ if (!link_sta)
+ mlink = &mvif->sta.deflink;
+
+ mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta, mlink);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
@@ -2028,7 +2023,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF,
sizeof(struct tlv));
} else {
- mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta);
+ if (!info->link_sta)
+ mlink = &mvif->sta.deflink;
+
+ mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta, mlink);
}
return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);
--
2.43.0
^ permalink raw reply related
* [PATCH 08/19] wifi: mt76: mt7925: validate mlink in sta_hdr_trans_tlv()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Replace the dead wcid NULL check in mt7925_mcu_sta_hdr_trans_tlv() with
a WARN_ON_ONCE() guard on mlink before dereferencing mlink->wcid.
wcid is always derived from mlink, so mlink is the only meaningful
object to validate here.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index c474dd358650..03515b891643 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1082,11 +1082,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
else
hdr_trans->from_ds = true;
- wcid = &mlink->wcid;
-
- if (!wcid)
+ if (WARN_ON_ONCE(!mlink))
return;
+ wcid = &mlink->wcid;
+
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;
--
2.43.0
^ permalink raw reply related
* [PATCH 09/19] wifi: mt76: mt7925: pass mlink to wtbl_update_hdr_trans()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_mcu_wtbl_update_hdr_trans()
and pass the resolved mlink from the caller instead. The link context is
already known at the call site, making the lookup redundant.
This keeps the helper lookup-free and makes link ownership explicit.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 8 ++------
drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 1 +
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index ddff6c5ab876..f5dd91dacca5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1598,7 +1598,7 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
if (!mlink->wcid.sta)
continue;
- mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i);
+ mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, mlink, i);
}
mt792x_mutex_release(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 03515b891643..0b096838bca6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1097,18 +1097,14 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
+ struct mt792x_link_sta *mlink,
int link_id)
{
- struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL;
- struct mt792x_link_sta *mlink;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_bss_conf *mconf;
- struct mt792x_sta *msta;
struct sk_buff *skb;
- msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta;
-
- mlink = mt792x_sta_to_link(msta, link_id);
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
mconf = mt792x_vif_to_link(mvif, link_id);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 95f29dae4d9d..e28972f0615b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -371,6 +371,7 @@ int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val);
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
+ struct mt792x_link_sta *mlink,
int link_id);
int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy);
--
2.43.0
^ permalink raw reply related
* [PATCH 10/19] wifi: mt76: mt7925: pass mlink to set_link_key()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_sta_to_link() lookup in mt7925_set_link_key() and pass
the resolved mlink from the caller instead. The link context is already
known at the call site, making the lookup redundant.
This keeps the helper lookup-free and makes link ownership explicit.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index f5dd91dacca5..68f168a093f2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -594,7 +594,8 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw,
static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key, int link_id)
+ struct ieee80211_key_conf *key, int link_id,
+ struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
@@ -603,7 +604,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_bss_conf *link_conf;
struct ieee80211_link_sta *link_sta;
int idx = key->keyidx, err = 0;
- struct mt792x_link_sta *mlink;
struct mt792x_bss_conf *mconf;
struct mt76_wcid *wcid;
u8 *wcid_keyidx;
@@ -611,7 +611,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL;
mconf = mt792x_vif_to_link(mvif, link_id);
- mlink = mt792x_sta_to_link(msta, link_id);
wcid = &mlink->wcid;
wcid_keyidx = &wcid->hw_key_idx;
@@ -679,6 +678,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv :
&mvif->sta;
+ struct mt792x_link_sta *mlink;
int err;
/* The hardware does not support per-STA RX GTK, fallback
@@ -700,12 +700,16 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links;
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
- err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id);
+ mlink = mt792x_sta_to_link(msta, link_id);
+ err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id,
+ mlink);
if (err < 0)
break;
}
} else {
- err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id);
+ mlink = mt792x_sta_to_link(msta, vif->bss_conf.link_id);
+ err = mt7925_set_link_key(hw, cmd, vif, sta, key,
+ vif->bss_conf.link_id, mlink);
}
mt792x_mutex_release(dev);
--
2.43.0
^ permalink raw reply related
* [PATCH 11/19] wifi: mt76: mt7925: resolve link after acquiring mt76 mutex
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
mt792x_sta_to_link() uses rcu_dereference_protected() and therefore
expects mt76.mutex to be held. Move the lookup after
mt792x_mutex_acquire() to make the locking explicit and correct.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 68f168a093f2..135a803b4382 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1071,11 +1071,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
struct mt792x_link_sta *mlink;
struct mt792x_sta *msta;
+ mt792x_mutex_acquire(dev);
+
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
- mt792x_mutex_acquire(dev);
-
if (ieee80211_vif_is_mld(vif)) {
link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id);
} else {
--
2.43.0
^ permalink raw reply related
* [PATCH 12/19] wifi: mt76: mt7925: pass mconf and mlink to wtbl_update_hdr_trans()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the mt792x_vif_to_link() lookup in mt7925_mcu_wtbl_update_hdr_trans()
and pass the resolved mconf and mlink from the caller instead. The link
context is already known at the call site, making the lookup redundant.
This keeps the helper lookup-free and makes link ownership explicit.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 4 +++-
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 20 ++++---------------
.../wireless/mediatek/mt76/mt7925/mt7925.h | 5 ++---
3 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 135a803b4382..151dc79f7c12 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1590,8 +1590,10 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0);
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt792x_bss_conf *mconf;
struct mt792x_link_sta *mlink;
+ mconf = mt792x_vif_to_link(mvif, i);
mlink = mt792x_sta_to_link(msta, i);
if (enabled)
@@ -1602,7 +1604,7 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
if (!mlink->wcid.sta)
continue;
- mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, mlink, i);
+ mt7925_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
}
mt792x_mutex_release(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 0b096838bca6..2be6160873a5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1066,7 +1066,6 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware);
static void
mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
- struct ieee80211_link_sta *link_sta,
struct mt792x_link_sta *mlink)
{
struct sta_rec_hdr_trans *hdr_trans;
@@ -1096,29 +1095,18 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct mt792x_link_sta *mlink,
- int link_id)
+ struct mt792x_bss_conf *mconf,
+ struct mt792x_link_sta *mlink)
{
- struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL;
- struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
- struct mt792x_bss_conf *mconf;
struct sk_buff *skb;
- link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
- mconf = mt792x_vif_to_link(mvif, link_id);
-
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
&mlink->wcid,
MT7925_STA_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
return PTR_ERR(skb);
- /* starec hdr trans */
- if (!link_sta)
- mlink = &mvif->sta.deflink;
-
- mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta, mlink);
+ mt7925_mcu_sta_hdr_trans_tlv(skb, vif, mlink);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
@@ -2022,7 +2010,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
if (!info->link_sta)
mlink = &mvif->sta.deflink;
- mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta, mlink);
+ mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, mlink);
}
return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index e28972f0615b..46b480f7d813 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -370,9 +370,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val);
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct mt792x_link_sta *mlink,
- int link_id);
+ struct mt792x_bss_conf *mconf,
+ struct mt792x_link_sta *mlink);
int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy);
int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
--
2.43.0
^ permalink raw reply related
* [PATCH 13/19] wifi: mt76: mt7925: make WCID cleanup unconditional in sta_remove_links()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Drop the dead pri_link check in mt7925_mac_sta_remove_links() and
perform WCID cleanup unconditionally.
mlink->pri_link is already cleared before the test, making the branch
ineffective. This matches the actual teardown behaviour and simplifies
the remove path.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 151dc79f7c12..584d989fb4e8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1221,10 +1221,8 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
mlink->sta = NULL;
mlink->pri_link = NULL;
- if (link_sta != mlink->pri_link) {
- mt76_wcid_cleanup(mdev, wcid);
- mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx);
- }
+ mt76_wcid_cleanup(mdev, wcid);
+ mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx);
if (msta->deflink_id == link_id)
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
--
2.43.0
^ permalink raw reply related
* [PATCH 14/19] wifi: mt76: mt7925: unwind WCID setup on link STA add failure
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Undo the published WCID state when mt7925_mac_link_sta_add() fails after
WCID setup.
The add path can fail after dev->mt76.wcid[] is published, so the error
path must clear the partial host-side WCID state to avoid leaving stale
entries behind.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 53 +++++++++++++------
1 file changed, 38 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 584d989fb4e8..dbde91727cd0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -862,8 +862,10 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
struct ieee80211_bss_conf *link_conf;
struct mt792x_bss_conf *mconf;
u8 link_id = link_sta->link_id;
+ bool wcid_published = false;
struct mt792x_sta *msta;
struct mt76_wcid *wcid;
+ bool pm_woken = false;
int ret, idx;
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
@@ -888,6 +890,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
wcid = &mlink->wcid;
ewma_signal_init(&wcid->rssi);
rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid);
+ wcid_published = true;
mt76_wcid_init(wcid, 0);
ewma_avg_signal_init(&mlink->avg_ack_signal);
memset(mlink->airtime_ac, 0,
@@ -895,7 +898,8 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
- return ret;
+ goto out_wcid;
+ pm_woken = true;
mt7925_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -909,15 +913,19 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
if (ieee80211_vif_is_mld(vif)) {
- mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta,
- mlink_bc->wcid.idx, mlink->wcid.idx,
- link_sta != mlink->pri_link);
+ ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta,
+ mlink_bc->wcid.idx, mlink->wcid.idx,
+ link_sta != mlink->pri_link);
+ if (ret)
+ goto out_pm;
} else {
- mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta,
- mlink_bc->wcid.idx, mlink->wcid.idx,
- false);
+ ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta,
+ mlink_bc->wcid.idx, mlink->wcid.idx,
+ false);
+ if (ret)
+ goto out_pm;
}
}
@@ -927,7 +935,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
mlink, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
- return ret;
+ goto out_pm;
} else if (ieee80211_vif_is_mld(vif) &&
link_sta != mlink->pri_link) {
struct mt792x_link_sta *pri_mlink;
@@ -940,31 +948,46 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
container_of(pri_wcid, struct mt792x_link_sta, wcid) :
NULL;
- if (WARN_ON_ONCE(!pri_mlink))
- return -EINVAL;
+ if (WARN_ON_ONCE(!pri_mlink)) {
+ ret = -EINVAL;
+ goto out_pm;
+ }
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
pri_mlink, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
- return ret;
+ goto out_pm;
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
- return ret;
+ goto out_pm;
} else {
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
- return ret;
+ goto out_pm;
}
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
return 0;
+
+out_pm:
+ if (pm_woken)
+ mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
+out_wcid:
+ if (wcid_published) {
+ u16 idx = wcid->idx;
+
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ mt76_wcid_cleanup(mdev, wcid);
+ mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx);
+ }
+ return ret;
}
static int
--
2.43.0
^ permalink raw reply related
* [PATCH 15/19] wifi: mt76: mt7925: drop WCID reinit after publish
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Remove the redundant mt76_wcid_init() call after publishing the WCID in
mt7925_mac_link_sta_add().
WCID is already initialized before publication, so reinitializing it
afterward is unnecessary and makes the setup ordering less clear.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index dbde91727cd0..d99dbd707fcd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -891,7 +891,6 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ewma_signal_init(&wcid->rssi);
rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid);
wcid_published = true;
- mt76_wcid_init(wcid, 0);
ewma_avg_signal_init(&mlink->avg_ack_signal);
memset(mlink->airtime_ac, 0,
sizeof(msta->deflink.airtime_ac));
--
2.43.0
^ permalink raw reply related
* [PATCH 16/19] wifi: mt76: mt7925: move WCID teardown into link_sta_remove()
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Move WCID teardown into mt7925_mac_link_sta_remove() to mirror the
dev->mt76.wcid[] publish done during link add.
This clears the published WCID before the rest of teardown, so WCID
lookups no longer expose a link that is being removed.
No functional change intended.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index d99dbd707fcd..9e3f3874d0b3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1151,12 +1151,14 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+ struct mt76_wcid *wcid = &mlink->wcid;
struct ieee80211_bss_conf *link_conf;
u8 link_id = link_sta->link_id;
+ u16 idx = wcid->idx;
mt7925_roc_abort_sync(dev);
- mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid);
+ mt76_connac_free_pending_tx_skbs(&dev->pm, wcid);
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false,
@@ -1183,6 +1185,10 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
list_del_init(&mlink->wcid.poll_list);
spin_unlock_bh(&mdev->sta_poll_lock);
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ mt76_wcid_cleanup(mdev, wcid);
+ mt76_wcid_mask_clear(mdev->wcid_mask, idx);
+
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
@@ -1191,8 +1197,6 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long old_links)
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
- struct mt76_dev *mdev = &dev->mt76;
- struct mt76_wcid *wcid;
unsigned int link_id;
/* clean up bss before starec */
@@ -1235,16 +1239,12 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
if (!mlink)
continue;
- mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink);
-
- wcid = &mlink->wcid;
rcu_assign_pointer(msta->link[link_id], NULL);
msta->valid_links &= ~BIT(link_id);
mlink->sta = NULL;
mlink->pri_link = NULL;
- mt76_wcid_cleanup(mdev, wcid);
- mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx);
+ mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink);
if (msta->deflink_id == link_id)
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
--
2.43.0
^ permalink raw reply related
* [PATCH 17/19] wifi: mt76: mt7925: switch link STA allocation to RCU lifetime
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Allocate mt792x_link_sta with kzalloc() and free it with kfree_rcu()
instead of devm-managed memory.
msta->link[] is published via RCU, so the link STA must remain valid
until readers have quiesced after teardown. Manage the object lifetime
with kfree_rcu() to match its RCU-visible publication.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 10 +++++++---
drivers/net/wireless/mediatek/mt76/mt792x.h | 1 +
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 9e3f3874d0b3..eb16c4683100 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1005,7 +1005,7 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
mlink = &msta->deflink;
msta->deflink_id = link_id;
} else {
- mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL);
+ mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
if (!mlink) {
err = -ENOMEM;
break;
@@ -1197,6 +1197,7 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long old_links)
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct mt76_dev *mdev = &dev->mt76;
unsigned int link_id;
/* clean up bss before starec */
@@ -1235,17 +1236,20 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
if (!link_sta)
continue;
- mlink = mt792x_sta_to_link(msta, link_id);
+ mlink = rcu_replace_pointer(msta->link[link_id], NULL,
+ lockdep_is_held(&mdev->mutex));
if (!mlink)
continue;
- rcu_assign_pointer(msta->link[link_id], NULL);
msta->valid_links &= ~BIT(link_id);
mlink->sta = NULL;
mlink->pri_link = NULL;
mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink);
+ if (mlink != &msta->deflink)
+ kfree_rcu(mlink, rcu_head);
+
if (msta->deflink_id == link_id)
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 1f381ab356bc..4ff93f2cd624 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -97,6 +97,7 @@ DECLARE_EWMA(avg_signal, 10, 8)
struct mt792x_link_sta {
struct mt76_wcid wcid; /* must be first */
+ struct rcu_head rcu_head;
u32 airtime_ac[8];
--
2.43.0
^ permalink raw reply related
* [PATCH 18/19] wifi: mt76: mt7925: publish msta->link after successful link add
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Move the msta->link[link_id] publication until after
mt7925_mac_link_sta_add() succeeds.
msta->link[] is RCU-visible, so publishing it before setup completes can
expose a link whose add path later fails. Publish it only after success
to avoid partially initialized link state becoming visible.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index eb16c4683100..95c631b57894 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1000,10 +1000,11 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_link_sta *link_sta;
struct mt792x_link_sta *mlink;
+ bool is_deflink = false;
if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) {
mlink = &msta->deflink;
- msta->deflink_id = link_id;
+ is_deflink = true;
} else {
mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
if (!mlink) {
@@ -1012,14 +1013,23 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
}
}
- msta->valid_links |= BIT(link_id);
- rcu_assign_pointer(msta->link[link_id], mlink);
mlink->sta = msta;
mlink->pri_link = &sta->deflink;
mlink->wcid.def_wcid = &msta->deflink.wcid;
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
- mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta, mlink);
+ err = mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta, mlink);
+ if (err) {
+ if (!is_deflink)
+ kfree_rcu(mlink, rcu_head);
+ break;
+ }
+
+ if (is_deflink)
+ msta->deflink_id = link_id;
+
+ rcu_assign_pointer(msta->link[link_id], mlink);
+ msta->valid_links |= BIT(link_id);
}
return err;
--
2.43.0
^ permalink raw reply related
* [PATCH 19/19] wifi: mt76: mt7925: host-only unwind published links on add failure
From: Sean Wang @ 2026-03-06 23:22 UTC (permalink / raw)
To: nbd, lorenzo.bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang
In-Reply-To: <20260306232238.2039675-1-sean.wang@kernel.org>
From: Sean Wang <sean.wang@mediatek.com>
Release host link resources when mt7925_mac_sta_add_links() fails after
partial success.
msta->link[] and dev->mt76.wcid[] may already be published, so unwind
the host state to avoid leaving stale links behind.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 95c631b57894..73d3722739d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -989,11 +989,51 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
return ret;
}
+/*
+ * Host-only unwind for sta_add_links() failures.
+ *
+ * If add_links fail due to MCU/firmware timeouts; calling the full remove
+ * path would send more firmware commands and may hang again. So only rollback
+ * host-published state here (msta->link/valid_links, dev->mt76.wcid[idx]) and
+ * free mlink objects (RCU-safe). Firmware state is left for reset/recovery.
+ */
+static void
+mt7925_mac_sta_unwind_links_host(struct mt792x_dev *dev,
+ struct ieee80211_sta *sta,
+ unsigned long links)
+{
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ unsigned int link_id;
+
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt792x_link_sta *mlink;
+ u16 idx;
+
+ mlink = rcu_replace_pointer(msta->link[link_id], NULL,
+ lockdep_is_held(&dev->mt76.mutex));
+ if (!mlink)
+ continue;
+
+ msta->valid_links &= ~BIT(link_id);
+ if (msta->deflink_id == link_id)
+ msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
+
+ idx = mlink->wcid.idx;
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx);
+
+ if (mlink != &msta->deflink)
+ kfree_rcu(mlink, rcu_head);
+ }
+}
+
static int
mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long new_links)
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ unsigned long added_links = 0;
unsigned int link_id;
int err = 0;
@@ -1030,8 +1070,13 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
rcu_assign_pointer(msta->link[link_id], mlink);
msta->valid_links |= BIT(link_id);
+
+ added_links |= BIT(link_id);
}
+ if (err && added_links)
+ mt7925_mac_sta_unwind_links_host(dev, sta, added_links);
+
return err;
}
--
2.43.0
^ permalink raw reply related
* [RFC 1/2] wifi: mac80211: Add force-cleanup call to driver.
From: greearb @ 2026-03-07 0:01 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
From: Ben Greear <greearb@candelatech.com>
When hardware is determined by mac80211 to be in non-recoverable
state, then SDATA_IN_DRIVER flag is removed, and mac80211 will no
longer do any 'graceful' teardown of the objects in the driver.
This was causing use-after-free crashes in the iwlwifi driver
since it's logic to do internal cleanup is not quite right for
some reason.
Add an explicit callback to the driver to tell it to clean up
whatever it needs to clean up in case mac80211 considers it
dead.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
RFC: I'm curious if something like this is wanted upstream?
include/net/mac80211.h | 7 +++++++
net/mac80211/driver-ops.h | 8 ++++++++
net/mac80211/util.c | 5 +++++
3 files changed, 20 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ae82fb5f2254..faa8c4f52794 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3942,6 +3942,12 @@ struct ieee80211_prep_tx_info {
* you should ensure to cancel it on this callback.
* Must be implemented and can sleep.
*
+ * @force_cleanup: Called after mac80211 determines the
+ * driver/firmware/hardware has failed and cannot
+ * be restarted. SDATA_IN_DRIVER is false at this point,
+ * so normal cleanup will not happen. This force_cleanup
+ * operation lets the driver do any needed houskeeping.
+ *
* @suspend: Suspend the device; mac80211 itself will quiesce before and
* stop transmitting and doing any other configuration, and then
* ask the device to suspend. This is only invoked when WoWLAN is
@@ -4584,6 +4590,7 @@ struct ieee80211_ops {
struct sk_buff *skb);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw, bool suspend);
+ void (*force_cleanup)(struct ieee80211_hw *hw);
#ifdef CONFIG_PM
int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
int (*resume)(struct ieee80211_hw *hw);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index fb98f6ea30a8..12970bdcf7b9 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -308,6 +308,14 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline void
+drv_force_cleanup(struct ieee80211_local *local)
+{
+ lockdep_assert_wiphy(local->hw.wiphy);
+ if (local->ops->force_cleanup)
+ local->ops->force_cleanup(&local->hw);
+}
+
static inline int
drv_sched_scan_start(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 1347e4933888..e2979c411c64 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1740,6 +1740,11 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
*/
list_for_each_entry(ctx, &local->chanctx_list, list)
ctx->driver_present = false;
+
+ /* Tell driver to purge any remaining configuration it may have
+ * lingering around.
+ */
+ drv_force_cleanup(local);
}
static void ieee80211_assign_chanctx(struct ieee80211_local *local,
--
2.42.0
^ permalink raw reply related
* [RFC 2/2] wifi: iwlwifi: mld: Support force-cleanup op
From: greearb @ 2026-03-07 0:01 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260307000131.2527892-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
This lets mac80211 force the driver to clean up any lingering
configuration, fixing use-after-free in case of unrecoverable
hardware failure.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 4102ee924757..d9ba77eb20eb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -500,6 +500,18 @@ iwl_mld_restart_cleanup(struct iwl_mld *mld)
ieee80211_wake_queues(mld->hw);
}
+/* mac80211 thinks our driver/firmware/hardware has crashed
+ * and cannot be recovered. Force clean any existing configuration
+ * (stas, etc), as mac80211 will not attempt further cleanup.
+ */
+static void iwl_mld_mac80211_force_cleanup(struct ieee80211_hw *hw)
+{
+ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
+
+ IWL_ERR(mld, "mac80211-force-cleanup called, calling mld_restart_cleanup.\n");
+ iwl_mld_restart_cleanup(mld);
+}
+
static
int iwl_mld_mac80211_start(struct ieee80211_hw *hw)
{
@@ -2963,6 +2975,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = {
.start = iwl_mld_mac80211_start,
.stop = iwl_mld_mac80211_stop,
.config = iwl_mld_mac80211_config,
+ .force_cleanup = iwl_mld_mac80211_force_cleanup,
.add_interface = iwl_mld_mac80211_add_interface,
.remove_interface = iwl_mld_mac80211_remove_interface,
.conf_tx = iwl_mld_mac80211_conf_tx,
--
2.42.0
^ permalink raw reply related
* [PATCH 00/18] wifi: mt76: mt7925: add MT7927 (Filogic 380) support
From: Javier Tia @ 2026-03-07 0:33 UTC (permalink / raw)
To: linux-wireless, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
Shayne Chen, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Deren Wu, Ming Yen Hsieh
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, Marcin FM,
Cristian-Florin Radoi, George Salukvadze, Evgeny Kapusta,
Samu Toljamo, Ariel Rosenfeld, Chapuis Dario,
Thibaut François, 张旭涵, Javier Tia
This series adds support for the MediaTek MT7927 (Filogic 380) combo
WiFi 7 + BT 5.4 module to the mt7925 driver. The MT7927 uses PCI ID
14c3:7927 (some hardware reports 14c3:6639) and shares the mt7925
firmware interface but requires different DMA ring layout, IRQ mapping,
chip initialization, and power management handling.
Tested hardware:
- ASUS ROG Crosshair X870E Hero (BT 0489:e13a, WiFi 14c3:6639)
- ASUS ProArt X870E-Creator WiFi (BT 0489:e13a / 13d3:3588, WiFi 14c3:6639)
- ASUS ROG Strix X870E-E (BT 0489:e13a, WiFi 14c3:7927)
- Gigabyte X870E Aorus Master X3D (BT 0489:e10f, WiFi 14c3:7927)
- Gigabyte Z790 AORUS MASTER X (BT 0489:e10f, WiFi 14c3:7927)
- Lenovo Legion Pro 7 16ARX9 (BT 0489:e0fa, WiFi 14c3:7927)
- TP-Link Archer TBE550E PCIe (BT 0489:e116, WiFi 14c3:7927)
- EDUP EP-MT7927BE M.2 card (WiFi 14c3:7927)
- Foxconn/Azurewave M.2 modules (WiFi 14c3:6639)
- AMD RZ738 reference design (WiFi 14c3:0738)
Tested on Arch Linux, CachyOS, EndeavourOS, Fedora (Bazzite), NixOS,
openSUSE Tumbleweed, and Ubuntu across kernels 6.13-6.19.
What works:
- WiFi 7 with EHT 320MHz on 2.4/5/6 GHz bands
- 320MHz data path verified at 841 Mbps (iperf3 -t30 -P8)
- PCIe initialization with CBTOP remap and MT7927-specific DMA layout
- Runtime power management and suspend/resume (S3)
- DBDC (dual-band concurrent) mode
- Explicit band_idx assignment for stable 5GHz/6GHz operation
- ASPM disabled for MT7927 to prevent throughput collapse
Known limitations (planned as follow-up series):
- MLO (Multi-Link Operation): tested working on 5GHz+2.4GHz STR
(776 Mbps) but requires additional patches for link lifetime
and error handling. Sean Wang's series [1] addresses these;
MLO support will be submitted as a follow-up on top of that.
[1] https://lore.kernel.org/linux-wireless/20260306232238.2039675-1-sean.wang@kernel.org/
- TX retransmissions: elevated retry rate on all bands, firmware-side
rate adaptation issue not addressable in the driver.
Patches 1-11 bring up the basic driver (chip ID, firmware, DMA, init,
power management, 320MHz MCS, mac_reset guard, IRQ map, probe fix).
Patch 12 advertises EHT 320MHz capabilities, guarded by is_mt7927().
Patches 13-14 fix DMASHDL PM wake and disable ASPM.
Patch 15 adds 320MHz bandwidth handling in RXV/TXS status reporting.
Patch 16 fixes stale pointer comparisons in change_vif_links.
Patch 17 assigns explicit band_idx for stable 5GHz/6GHz operation.
Patch 18 adds the missing 320MHz case in bss_rlm_tlv() so firmware
receives the correct bandwidth when associated to a 320MHz BSS.
The WiFi firmware ships as part of the linux-firmware package
(mediatek/mt6639/ directory - the firmware uses the mobile SoC codename).
To: linux-wireless@vger.kernel.org
To: Felix Fietkau <nbd@nbd.name>
To: Lorenzo Bianconi <lorenzo@kernel.org>
To: Ryder Lee <ryder.lee@mediatek.com>
To: Shayne Chen <shayne.chen@mediatek.com>
To: Sean Wang <sean.wang@mediatek.com>
To: Matthias Brugger <matthias.bgg@gmail.com>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
To: Deren Wu <deren.wu@mediatek.com>
To: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-mediatek@lists.infradead.org
Tested-by: Marcin FM <marcin@lgic.pl>
Tested-by: Cristian-Florin Radoi <radoi.chris@gmail.com>
Tested-by: George Salukvadze <giosal90@gmail.com>
Tested-by: Evgeny Kapusta <3193631@gmail.com>
Tested-by: Samu Toljamo <samu.toljamo@gmail.com>
Tested-by: Ariel Rosenfeld <ariel.rosenfeld.750@gmail.com>
Tested-by: Chapuis Dario <chapuisdario4@gmail.com>
Tested-by: Thibaut François <tibo@humeurlibre.fr>
Tested-by: 张旭涵 <Loong.0x00@gmail.com>
Signed-off-by: Javier Tia <floss@jetm.me>
---
Javier Tia (18):
wifi: mt76: mt7925: add MT7927 chip ID helpers
wifi: mt76: mt7925: add MT7927 firmware paths and PCI device IDs
wifi: mt76: mt7925: add MT7927 CBTOP remap and chip initialization
wifi: mt76: mt7925: add MT7927 DMA ring layout, IRQ map, and prefetch
wifi: mt76: mt7925: skip CLR_OWN in mt7925e_mcu_init for MT7927
wifi: mt76: mt7925: add MT7927 power management, DBDC, and CNM fixes
wifi: mt76: mt7925: use irq_map fields instead of MT_INT_RX_DONE_ALL
wifi: mt76: mt7925: guard mac_reset against MT7927 DMA destruction
wifi: mt76: mt7925: populate EHT 320MHz MCS map in sta_rec
wifi: mt76: mt7925: enable MT7927 runtime power management
wifi: mt76: mt7925: fix uninitialized is_mt7927_hw in probe
wifi: mt76: mt7925: advertise EHT 320MHz capabilities for 6GHz band
wifi: mt76: mt7925: restore FW_DWLD_BYPASS_DMASHDL in MT7927 PM wake path
wifi: mt76: mt7925: disable ASPM for MT7927 to fix throughput collapse
wifi: mt76: mt7925: handle 320MHz bandwidth in RXV and TXS
wifi: mt76: mt7925: fix stale pointer comparisons in change_vif_links
wifi: mt76: mt7925: fix MT7927 band_idx for stable 5GHz/6GHz operation
wifi: mt76: mt7925: add 320MHz bandwidth to bss_rlm_tlv
drivers/net/wireless/mediatek/mt76/mt76_connac.h | 8 +-
drivers/net/wireless/mediatek/mt76/mt7925/init.c | 12 +
drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 9 +
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 72 +++++-
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 59 ++++-
drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 12 +
drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 248 ++++++++++++++++++++-
.../net/wireless/mediatek/mt76/mt7925/pci_mac.c | 13 +-
.../net/wireless/mediatek/mt76/mt7925/pci_mcu.c | 19 +-
drivers/net/wireless/mediatek/mt76/mt792x.h | 6 +
drivers/net/wireless/mediatek/mt76/mt792x_dma.c | 26 ++-
drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 30 +++
12 files changed, 479 insertions(+), 35 deletions(-)
---
base-commit: 97492c019da4b62df83255e968b23b81c0315530
change-id: 20260305-mt7927-wifi-support-02f9738a3962
Best regards,
--
Javier Tia <floss@jetm.me>
^ permalink raw reply
* [PATCH 01/18] wifi: mt76: mt7925: add MT7927 chip ID helpers
From: Javier Tia @ 2026-03-07 0:33 UTC (permalink / raw)
To: linux-wireless, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
Shayne Chen, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Deren Wu, Ming Yen Hsieh
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, Marcin FM,
Cristian-Florin Radoi, George Salukvadze, Evgeny Kapusta,
Samu Toljamo, Ariel Rosenfeld, Chapuis Dario,
Thibaut François, 张旭涵, Javier Tia
In-Reply-To: <20260306-mt7927-wifi-support-v1-0-c77e7445511d@jetm.me>
The MediaTek MT7927 (Filogic 380) combo chip uses MT7927 WiFi silicon
that is architecturally compatible with MT7925. Extend is_mt7925() to
match chip ID 0x7927, and add is_mt7927() for code paths that need
MT7927-specific handling.
Also add 0x7927 to is_mt76_fw_txp() to match MT7925's TXP format.
Tested-by: Marcin FM <marcin@lgic.pl>
Tested-by: Cristian-Florin Radoi <radoi.chris@gmail.com>
Tested-by: George Salukvadze <giosal90@gmail.com>
Tested-by: Evgeny Kapusta <3193631@gmail.com>
Tested-by: Samu Toljamo <samu.toljamo@gmail.com>
Tested-by: Ariel Rosenfeld <ariel.rosenfeld.750@gmail.com>
Tested-by: Chapuis Dario <chapuisdario4@gmail.com>
Tested-by: Thibaut François <tibo@humeurlibre.fr>
Tested-by: 张旭涵 <Loong.0x00@gmail.com>
Signed-off-by: Javier Tia <floss@jetm.me>
---
drivers/net/wireless/mediatek/mt76/mt76_connac.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 813d61bffc2c..bfd5b05c2b20 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -174,7 +174,12 @@ extern const struct wiphy_wowlan_support mt76_connac_wowlan_support;
static inline bool is_mt7925(struct mt76_dev *dev)
{
- return mt76_chip(dev) == 0x7925;
+ return mt76_chip(dev) == 0x7925 || mt76_chip(dev) == 0x7927;
+}
+
+static inline bool is_mt7927(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7927;
}
static inline bool is_mt7920(struct mt76_dev *dev)
@@ -272,6 +277,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
case 0x7920:
case 0x7922:
case 0x7925:
+ case 0x7927:
case 0x7663:
case 0x7622:
return false;
--
2.53.0
^ permalink raw reply related
* [PATCH 02/18] wifi: mt76: mt7925: add MT7927 firmware paths and PCI device IDs
From: Javier Tia @ 2026-03-07 0:33 UTC (permalink / raw)
To: linux-wireless, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
Shayne Chen, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Deren Wu, Ming Yen Hsieh
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, Marcin FM,
Cristian-Florin Radoi, George Salukvadze, Evgeny Kapusta,
Samu Toljamo, Ariel Rosenfeld, Chapuis Dario,
Thibaut François, 张旭涵, Javier Tia
In-Reply-To: <20260306-mt7927-wifi-support-v1-0-c77e7445511d@jetm.me>
Add PCI device IDs for MT7927 (14c3:7927) and MT7927 (14c3:6639)
hardware variants, along with firmware path definitions for the MT7927
WiFi firmware.
Known hardware using these IDs:
- ASUS ROG Crosshair X870E Hero (14c3:7927)
- Lenovo Legion Pro 7 16ARX9 (14c3:7927)
- Foxconn/Azurewave modules (14c3:6639)
- AMD RZ738 (MediaTek MT7927) (14c3:0738)
Tested-by: Marcin FM <marcin@lgic.pl>
Tested-by: Cristian-Florin Radoi <radoi.chris@gmail.com>
Tested-by: George Salukvadze <giosal90@gmail.com>
Tested-by: Evgeny Kapusta <3193631@gmail.com>
Tested-by: Samu Toljamo <samu.toljamo@gmail.com>
Tested-by: Ariel Rosenfeld <ariel.rosenfeld.750@gmail.com>
Tested-by: Chapuis Dario <chapuisdario4@gmail.com>
Tested-by: Thibaut François <tibo@humeurlibre.fr>
Tested-by: 张旭涵 <Loong.0x00@gmail.com>
Signed-off-by: Javier Tia <floss@jetm.me>
---
drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 6 ++++++
drivers/net/wireless/mediatek/mt76/mt792x.h | 6 ++++++
2 files changed, 12 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index c4161754c01d..54eac5c6e509 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -16,6 +16,10 @@ static const struct pci_device_id mt7925_pci_device_table[] = {
.driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM },
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0717),
.driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7927),
+ .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x6639),
+ .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM },
{ },
};
@@ -633,6 +637,8 @@ module_pci_driver(mt7925_pci_driver);
MODULE_DEVICE_TABLE(pci, mt7925_pci_device_table);
MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
MODULE_FIRMWARE(MT7925_ROM_PATCH);
+MODULE_FIRMWARE(MT7927_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7927_ROM_PATCH);
MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver");
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 8388638ed550..38790ef83e51 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -45,11 +45,13 @@
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin"
#define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin"
+#define MT7927_FIRMWARE_WM "mediatek/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin"
#define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin"
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin"
#define MT7925_ROM_PATCH "mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin"
+#define MT7927_ROM_PATCH "mediatek/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin"
#define MT792x_SDIO_HDR_TX_BYTES GENMASK(15, 0)
#define MT792x_SDIO_HDR_PKT_TYPE GENMASK(17, 16)
@@ -454,6 +456,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev)
return MT7922_FIRMWARE_WM;
case 0x7925:
return MT7925_FIRMWARE_WM;
+ case 0x7927:
+ return MT7927_FIRMWARE_WM;
default:
return MT7921_FIRMWARE_WM;
}
@@ -468,6 +472,8 @@ static inline char *mt792x_patch_name(struct mt792x_dev *dev)
return MT7922_ROM_PATCH;
case 0x7925:
return MT7925_ROM_PATCH;
+ case 0x7927:
+ return MT7927_ROM_PATCH;
default:
return MT7921_ROM_PATCH;
}
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox