mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-03 17:51:23 +00:00
wifi: mt76: mt7921: introduce CSA support
Add CSA (Channel Switch Announcement) related implementation in collaboration with mac80211 to deal with dynamic channel switching. Signed-off-by: Leon Yen <leon.yen@mediatek.com> Signed-off-by: Ming Yen Hsieh <mingyen.hsieh@mediatek.com> Link: https://patch.msgid.link/20241107061440.6545-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
efeaabc568
commit
8aa2f59260
@ -339,6 +339,9 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
|
||||
if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN)
|
||||
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI;
|
||||
|
||||
INIT_WORK(&mvif->csa_work, mt7921_csa_work);
|
||||
timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0);
|
||||
out:
|
||||
mt792x_mutex_release(dev);
|
||||
|
||||
@ -1342,6 +1345,9 @@ static int
|
||||
mt7921_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;
|
||||
}
|
||||
|
||||
@ -1349,6 +1355,10 @@ static void
|
||||
mt7921_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
|
||||
@ -1399,6 +1409,89 @@ static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw,
|
||||
mt7921_abort_roc(mvif->phy, mvif);
|
||||
}
|
||||
|
||||
static int mt7921_switch_vif_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif_chanctx_switch *vifs,
|
||||
int n_vifs,
|
||||
enum ieee80211_chanctx_switch_mode mode)
|
||||
{
|
||||
return mt792x_assign_vif_chanctx(hw, vifs->vif, vifs->link_conf,
|
||||
vifs->new_ctx);
|
||||
}
|
||||
|
||||
void mt7921_csa_work(struct work_struct *work)
|
||||
{
|
||||
struct mt792x_vif *mvif;
|
||||
struct mt792x_dev *dev;
|
||||
struct ieee80211_vif *vif;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
ret = mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76,
|
||||
dev->new_ctx);
|
||||
mt792x_mutex_release(dev);
|
||||
|
||||
ieee80211_chswitch_done(vif, !ret, 0);
|
||||
}
|
||||
|
||||
static int mt7921_pre_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel_switch *chsw)
|
||||
{
|
||||
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Avoid beacon loss due to the CAC(Channel Availability Check) time
|
||||
* of the AP.
|
||||
*/
|
||||
if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef,
|
||||
IEEE80211_CHAN_RADAR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt7921_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 = vif->bss_conf.beacon_int;
|
||||
|
||||
mvif->csa_timer.expires = TU_TO_EXP_TIME(beacon_interval * chsw->count);
|
||||
add_timer(&mvif->csa_timer);
|
||||
}
|
||||
|
||||
static void mt7921_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;
|
||||
|
||||
del_timer_sync(&mvif->csa_timer);
|
||||
cancel_work_sync(&mvif->csa_work);
|
||||
}
|
||||
|
||||
static void mt7921_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 = 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 mt7921_ops = {
|
||||
.tx = mt792x_tx,
|
||||
.start = mt7921_start,
|
||||
@ -1458,6 +1551,11 @@ const struct ieee80211_ops mt7921_ops = {
|
||||
.unassign_vif_chanctx = mt792x_unassign_vif_chanctx,
|
||||
.mgd_prepare_tx = mt7921_mgd_prepare_tx,
|
||||
.mgd_complete_tx = mt7921_mgd_complete_tx,
|
||||
.switch_vif_chanctx = mt7921_switch_vif_chanctx,
|
||||
.pre_channel_switch = mt7921_pre_channel_switch,
|
||||
.channel_switch = mt7921_channel_switch,
|
||||
.abort_channel_switch = mt7921_abort_channel_switch,
|
||||
.channel_switch_rx_beacon = mt7921_channel_switch_rx_beacon,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mt7921_ops);
|
||||
|
||||
|
@ -273,6 +273,7 @@ int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev,
|
||||
bool enable);
|
||||
void mt7921_scan_work(struct work_struct *work);
|
||||
void mt7921_roc_work(struct work_struct *work);
|
||||
void mt7921_csa_work(struct work_struct *work);
|
||||
int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif);
|
||||
void mt7921_coredump_work(struct work_struct *work);
|
||||
int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr);
|
||||
|
@ -133,6 +133,9 @@ struct mt792x_vif {
|
||||
struct mt792x_phy *phy;
|
||||
u16 valid_links;
|
||||
u8 deflink_id;
|
||||
|
||||
struct work_struct csa_work;
|
||||
struct timer_list csa_timer;
|
||||
};
|
||||
|
||||
struct mt792x_phy {
|
||||
@ -237,6 +240,8 @@ struct mt792x_dev {
|
||||
enum environment_cap country_ie_env;
|
||||
u32 backup_l1;
|
||||
u32 backup_l2;
|
||||
|
||||
struct ieee80211_chanctx_conf *new_ctx;
|
||||
};
|
||||
|
||||
static inline struct mt792x_bss_conf *
|
||||
@ -369,6 +374,7 @@ void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u64 timestamp);
|
||||
void mt792x_tx_worker(struct mt76_worker *w);
|
||||
void mt792x_roc_timer(struct timer_list *timer);
|
||||
void mt792x_csa_timer(struct timer_list *timer);
|
||||
void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u32 queues, bool drop);
|
||||
int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
|
@ -289,6 +289,14 @@ void mt792x_roc_timer(struct timer_list *timer)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt792x_roc_timer);
|
||||
|
||||
void mt792x_csa_timer(struct timer_list *timer)
|
||||
{
|
||||
struct mt792x_vif *mvif = from_timer(mvif, timer, csa_timer);
|
||||
|
||||
ieee80211_queue_work(mvif->phy->mt76->hw, &mvif->csa_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt792x_csa_timer);
|
||||
|
||||
void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u32 queues, bool drop)
|
||||
{
|
||||
@ -330,6 +338,11 @@ void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
mctx->bss_conf = NULL;
|
||||
mvif->bss_conf.mt76.ctx = NULL;
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
if (vif->bss_conf.csa_active) {
|
||||
del_timer_sync(&mvif->csa_timer);
|
||||
cancel_work_sync(&mvif->csa_work);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt792x_unassign_vif_chanctx);
|
||||
|
||||
@ -652,6 +665,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
|
||||
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
|
||||
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
|
||||
ieee80211_hw_set(hw, CONNECTION_MONITOR);
|
||||
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
|
||||
|
||||
if (dev->pm.enable)
|
||||
ieee80211_hw_set(hw, CONNECTION_MONITOR);
|
||||
|
Loading…
Reference in New Issue
Block a user