wifi: mt76: mt7925: introduce CSA support in non-MLO mode

Add CSA (Channel Switch Announcement) related implementation
in collaboration with mac80211 to deal with dynamic channel
switching.

Signed-off-by: Leon Yen <[email protected]>
Signed-off-by: Ming Yen Hsieh <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Leon Yen
2026-01-27 10:07:55 +00:00
committed by Felix Fietkau
parent 82c085f95a
commit 7b76bbba59
3 changed files with 142 additions and 3 deletions
+139
View File
@@ -245,6 +245,7 @@ int mt7925_init_mlo_caps(struct mt792x_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
static const u8 ext_capa_sta[] = {
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
};
@@ -438,6 +439,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN)
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI;
INIT_WORK(&mvif->csa_work, mt7925_csa_work);
timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0);
out:
mt792x_mutex_release(dev);
@@ -1749,6 +1753,10 @@ static int
mt7925_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
dev->new_ctx = ctx;
return 0;
}
@@ -1756,6 +1764,11 @@ static void
mt7925_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
if (dev->new_ctx == ctx)
dev->new_ctx = NULL;
}
static void
@@ -2144,6 +2157,11 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw,
mctx->bss_conf = NULL;
mconf->mt76.ctx = NULL;
mutex_unlock(&dev->mt76.mutex);
if (link_conf->csa_active) {
timer_delete_sync(&mvif->csa_timer);
cancel_work_sync(&mvif->csa_work);
}
}
static void mt7925_rfkill_poll(struct ieee80211_hw *hw)
@@ -2158,6 +2176,121 @@ static void mt7925_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(hw->wiphy, ret == 0);
}
static int mt7925_switch_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
return mt7925_assign_vif_chanctx(hw, vifs->vif, vifs->link_conf,
vifs->new_ctx);
}
void mt7925_csa_work(struct work_struct *work)
{
struct mt792x_vif *mvif;
struct mt792x_dev *dev;
struct ieee80211_vif *vif;
struct ieee80211_bss_conf *link_conf;
struct mt792x_bss_conf *mconf;
u8 link_id, roc_rtype;
int ret = 0;
mvif = (struct mt792x_vif *)container_of(work, struct mt792x_vif,
csa_work);
dev = mvif->phy->dev;
vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
if (ieee80211_vif_is_mld(vif))
return;
if (!dev->new_ctx)
return;
link_id = 0;
mconf = &mvif->bss_conf;
link_conf = &vif->bss_conf;
roc_rtype = MT7925_ROC_REQ_JOIN;
mt792x_mutex_acquire(dev);
ret = mt7925_set_roc(mvif->phy, mconf, dev->new_ctx->def.chan,
4000, roc_rtype);
mt792x_mutex_release(dev);
if (!ret) {
mt792x_mutex_acquire(dev);
ret = mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, link_conf,
dev->new_ctx);
mt792x_mutex_release(dev);
mt7925_abort_roc(mvif->phy, mconf);
}
ieee80211_chswitch_done(vif, !ret, link_id);
}
static int mt7925_pre_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
if (ieee80211_vif_is_mld(vif))
return -EOPNOTSUPP;
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
return -EOPNOTSUPP;
if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef,
IEEE80211_CHAN_DISABLED))
return -EOPNOTSUPP;
return 0;
}
static void mt7925_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
u16 beacon_interval;
if (ieee80211_vif_is_mld(vif))
return;
beacon_interval = vif->bss_conf.beacon_int;
mvif->csa_timer.expires = TU_TO_EXP_TIME(beacon_interval * chsw->count);
add_timer(&mvif->csa_timer);
}
static void mt7925_abort_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
timer_delete_sync(&mvif->csa_timer);
cancel_work_sync(&mvif->csa_work);
}
static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
u16 beacon_interval;
if (ieee80211_vif_is_mld(vif))
return;
beacon_interval = vif->bss_conf.beacon_int;
if (cfg80211_chandef_identical(&chsw->chandef,
&dev->new_ctx->def) &&
chsw->count) {
mod_timer(&mvif->csa_timer,
TU_TO_EXP_TIME(beacon_interval * chsw->count));
}
}
const struct ieee80211_ops mt7925_ops = {
.tx = mt792x_tx,
.start = mt7925_start,
@@ -2221,6 +2354,12 @@ const struct ieee80211_ops mt7925_ops = {
.change_vif_links = mt7925_change_vif_links,
.change_sta_links = mt7925_change_sta_links,
.rfkill_poll = mt7925_rfkill_poll,
.switch_vif_chanctx = mt7925_switch_vif_chanctx,
.pre_channel_switch = mt7925_pre_channel_switch,
.channel_switch = mt7925_channel_switch,
.abort_channel_switch = mt7925_abort_channel_switch,
.channel_switch_rx_beacon = mt7925_channel_switch_rx_beacon,
};
EXPORT_SYMBOL_GPL(mt7925_ops);
+1
View File
@@ -298,6 +298,7 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev,
void mt7925_mlo_pm_work(struct work_struct *work);
void mt7925_scan_work(struct work_struct *work);
void mt7925_roc_work(struct work_struct *work);
void mt7925_csa_work(struct work_struct *work);
int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev,
struct ieee80211_bss_conf *link_conf);
void mt7925_coredump_work(struct work_struct *work);
+2 -3
View File
@@ -691,9 +691,8 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID);
if (is_mt7921(&dev->mt76)) {
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
}
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
if (dev->pm.enable)
ieee80211_hw_set(hw, CONNECTION_MONITOR);