mirror of
https://github.com/torvalds/linux.git
synced 2026-10-08 19:46:02 +02:00
wifi: mt76: fix handling channel context with different bands in mt76_switch_vif_chanctx()
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: 82334623af ("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>
Link: https://patch.msgid.link/20260720090102.190729-1-shayne.chen@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
965cbdbdfb
commit
70869cc429
|
|
@ -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;
|
||||
|
||||
if (update_chan)
|
||||
ret = mt76_phy_update_channel(phy, vifs->new_ctx);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (old_phy == phy)
|
||||
goto skip_link_replace;
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
|
||||
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 (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && old_phy->chanctx &&
|
||||
old_phy->chanctx == old_ctx && phy != old_phy)
|
||||
old_phy->chanctx = NULL;
|
||||
|
||||
if (need_update[phy->band_idx]) {
|
||||
ret = mt76_phy_update_channel(phy, v->new_ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
need_update[phy->band_idx] = false;
|
||||
}
|
||||
|
||||
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);
|
||||
if (old_phy != phy) {
|
||||
dev->drv->vif_link_remove(old_phy, v->vif, v->link_conf,
|
||||
mlink);
|
||||
|
||||
ret = dev->drv->vif_link_add(phy, vifs[i].vif,
|
||||
vifs[i].link_conf, mlink);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = dev->drv->vif_link_add(phy, v->vif, v->link_conf,
|
||||
mlink);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
mlink->ctx = vifs->new_ctx;
|
||||
mlink->ctx = v->new_ctx;
|
||||
if (mlink->beacon_mon_interval)
|
||||
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user