From: Shayne Chen <shayne.chen@mediatek.com>
To: Felix Fietkau <nbd@nbd.name>
Cc: linux-wireless <linux-wireless@vger.kernel.org>,
Lorenzo Bianconi <lorenzo@kernel.org>,
Ryder Lee <ryder.lee@mediatek.com>,
Evelyn Tsai <evelyn.tsai@mediatek.com>,
Money Wang <money.wang@mediatek.com>,
linux-mediatek <linux-mediatek@lists.infradead.org>,
Shayne Chen <shayne.chen@mediatek.com>,
Rex Lu <rex.lu@mediatek.com>
Subject: [PATCH mt76 v2] wifi: mt76: fix handling channel context with different bands in mt76_switch_vif_chanctx()
Date: Mon, 20 Jul 2026 17:01:02 +0800 [thread overview]
Message-ID: <20260720090102.190729-1-shayne.chen@mediatek.com> (raw)
When performing channel switches on different radios within a short
timeframe, channel contexts with different bands can be carried for
each struct ieee80211_vif_chanctx_switch.
Rework mt76_switch_vif_chanctx() to properly handle this scenario.
Fixes: 82334623af0c ("wifi: mt76: add chanctx functions for multi-channel phy support")
Co-developed-by: Rex Lu <rex.lu@mediatek.com>
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
v2:
- prevent from doing duplicated works if need_update[band] is marked
---
drivers/net/wireless/mediatek/mt76/channel.c | 92 +++++++++++---------
1 file changed, 49 insertions(+), 43 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c
index 6edcb3b8f279..28ad7bcaffd4 100644
--- a/drivers/net/wireless/mediatek/mt76/channel.c
+++ b/drivers/net/wireless/mediatek/mt76/channel.c
@@ -186,68 +186,74 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
- struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv;
- struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv;
- struct ieee80211_chanctx_conf *conf = vifs->new_ctx;
- struct mt76_phy *old_phy = old_ctx->phy;
- struct mt76_phy *phy = hw->priv;
+ struct ieee80211_vif_chanctx_switch *v;
+ struct mt76_chanctx *old_ctx, *new_ctx;
+ struct mt76_phy *old_phy, *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
struct mt76_vif_link *mlink;
- bool update_chan;
+ bool need_update[__MT_MAX_BAND] = {};
int i, ret = 0;
- if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
- phy = new_ctx->phy = dev->band_phys[conf->def.chan->band];
- else
- phy = new_ctx->phy;
- if (!phy)
- return -EINVAL;
+ for (i = 0; i < n_vifs; i++) {
+ v = &vifs[i];
+ new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv;
+ if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
+ phy = new_ctx->phy = dev->band_phys[v->new_ctx->def.chan->band];
+ else
+ phy = new_ctx->phy;
- update_chan = phy->chanctx != new_ctx;
- if (update_chan) {
- if (dev->scan.phy == phy)
- mt76_abort_scan(dev);
+ if (!phy)
+ return -EINVAL;
- cancel_delayed_work_sync(&phy->mac_work);
+ if (need_update[phy->band_idx])
+ continue;
+
+ if (phy->chanctx != new_ctx) {
+ if (dev->scan.phy == phy)
+ mt76_abort_scan(dev);
+
+ cancel_delayed_work_sync(&phy->mac_work);
+ need_update[phy->band_idx] = true;
+ }
}
mutex_lock(&dev->mutex);
- if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
- phy != old_phy && old_phy->chanctx == old_ctx)
- old_phy->chanctx = NULL;
+ for (i = 0; i < n_vifs; i++) {
+ v = &vifs[i];
+ old_ctx = (struct mt76_chanctx *)v->old_ctx->drv_priv;
+ old_phy = old_ctx->phy;
+
+ new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv;
+ phy = new_ctx->phy;
- if (update_chan)
- ret = mt76_phy_update_channel(phy, vifs->new_ctx);
+ if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && old_phy->chanctx &&
+ old_phy->chanctx == old_ctx && phy != old_phy)
+ old_phy->chanctx = NULL;
- if (ret)
- goto out;
+ if (need_update[phy->band_idx]) {
+ ret = mt76_phy_update_channel(phy, v->new_ctx);
+ if (ret)
+ goto out;
- if (old_phy == phy)
- goto skip_link_replace;
+ need_update[phy->band_idx] = false;
+ }
- for (i = 0; i < n_vifs; i++) {
- mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
+ mlink = mt76_vif_conf_link(dev, v->vif, v->link_conf);
if (!mlink)
continue;
- dev->drv->vif_link_remove(old_phy, vifs[i].vif,
- vifs[i].link_conf, mlink);
-
- ret = dev->drv->vif_link_add(phy, vifs[i].vif,
- vifs[i].link_conf, mlink);
- if (ret)
- goto out;
-
- }
+ if (old_phy != phy) {
+ dev->drv->vif_link_remove(old_phy, v->vif, v->link_conf,
+ mlink);
-skip_link_replace:
- for (i = 0; i < n_vifs; i++) {
- mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
- if (!mlink)
- continue;
+ ret = dev->drv->vif_link_add(phy, v->vif, v->link_conf,
+ mlink);
+ if (ret)
+ goto out;
+ }
- mlink->ctx = vifs->new_ctx;
+ mlink->ctx = v->new_ctx;
if (mlink->beacon_mon_interval)
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
}
--
2.51.0
reply other threads:[~2026-07-20 9:01 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260720090102.190729-1-shayne.chen@mediatek.com \
--to=shayne.chen@mediatek.com \
--cc=evelyn.tsai@mediatek.com \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=lorenzo@kernel.org \
--cc=money.wang@mediatek.com \
--cc=nbd@nbd.name \
--cc=rex.lu@mediatek.com \
--cc=ryder.lee@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox