mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 03:53:37 +02:00
wifi: rtw89: implement channel switch support
To support channel switch on STA mode, declare IEEE80211_HW_CHANCTX_STA_CSA and implement ieee80211_ops::switch_vif_chanctx. Handling of CSA procedure still relies on mac80211 SW flow, since FW doesn't support chanctx offload. To support channel switch on AP mode, declare WIPHY_FLAG_HAS_CHANNEL_SWITCH and implement ieee80211_ops::channel_switch_beacon additionally. Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20250605114207.12381-4-pkshih@realtek.com
This commit is contained in:
parent
6c661eec29
commit
edba3f1078
|
|
@ -2912,3 +2912,35 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link,
|
||||
struct ieee80211_chanctx_conf *old_ctx,
|
||||
struct ieee80211_chanctx_conf *new_ctx,
|
||||
bool replace)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, old_ctx);
|
||||
|
||||
if (!replace)
|
||||
goto assign;
|
||||
|
||||
rtw89_chanctx_ops_remove(rtwdev, old_ctx);
|
||||
ret = rtw89_chanctx_ops_add(rtwdev, new_ctx);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "%s: failed to add chanctx: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
assign:
|
||||
ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, new_ctx);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "%s: failed to assign chanctx: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,5 +143,10 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
|
|||
void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link,
|
||||
struct ieee80211_chanctx_conf *ctx);
|
||||
int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link,
|
||||
struct ieee80211_chanctx_conf *old_ctx,
|
||||
struct ieee80211_chanctx_conf *new_ctx,
|
||||
bool replace);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
|
|||
};
|
||||
|
||||
static const u8 rtw89_ext_capa_sta[] = {
|
||||
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
|
||||
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
||||
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||
};
|
||||
|
|
@ -4655,6 +4656,43 @@ void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work)
|
|||
rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link);
|
||||
}
|
||||
|
||||
void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link =
|
||||
container_of(work, struct rtw89_vif_link, csa_beacon_work.work);
|
||||
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
|
||||
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
|
||||
struct rtw89_dev *rtwdev = rtwvif->rtwdev;
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
unsigned int delay;
|
||||
|
||||
lockdep_assert_wiphy(wiphy);
|
||||
|
||||
if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
|
||||
if (!bss_conf->csa_active) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
delay = ieee80211_tu_to_usec(bss_conf->beacon_int);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!ieee80211_beacon_cntdwn_is_complete(vif, rtwvif_link->link_id)) {
|
||||
rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link);
|
||||
|
||||
wiphy_delayed_work_queue(wiphy, &rtwvif_link->csa_beacon_work,
|
||||
usecs_to_jiffies(delay));
|
||||
} else {
|
||||
ieee80211_csa_finish(vif, rtwvif_link->link_id);
|
||||
}
|
||||
}
|
||||
|
||||
int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
|
||||
{
|
||||
struct completion *cmpl = &wait->completion;
|
||||
|
|
@ -5505,6 +5543,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
|
|||
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
|
||||
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
|
||||
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
|
||||
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
|
||||
|
||||
if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
|
||||
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
|
||||
|
|
@ -5531,6 +5570,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
|
|||
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
|
||||
WIPHY_FLAG_TDLS_EXTERNAL_SETUP |
|
||||
WIPHY_FLAG_AP_UAPSD |
|
||||
WIPHY_FLAG_HAS_CHANNEL_SWITCH |
|
||||
WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK;
|
||||
|
||||
if (!chip->support_rnr)
|
||||
|
|
|
|||
|
|
@ -3533,6 +3533,7 @@ struct rtw89_vif_link {
|
|||
bool pwr_diff_en;
|
||||
u8 def_tri_idx;
|
||||
struct wiphy_work update_beacon_work;
|
||||
struct wiphy_delayed_work csa_beacon_work;
|
||||
struct rtw89_addr_cam_entry addr_cam;
|
||||
struct rtw89_bssid_cam_entry bssid_cam;
|
||||
struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS];
|
||||
|
|
@ -7317,6 +7318,7 @@ void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
|
|||
int rtw89_core_start(struct rtw89_dev *rtwdev);
|
||||
void rtw89_core_stop(struct rtw89_dev *rtwdev);
|
||||
void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work);
|
||||
void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work);
|
||||
void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work);
|
||||
void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
|
||||
void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev,
|
|||
rtw89_vif_type_mapping(rtwvif_link, false);
|
||||
|
||||
wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work);
|
||||
wiphy_delayed_work_init(&rtwvif_link->csa_beacon_work, rtw89_core_csa_beacon_work);
|
||||
|
||||
INIT_LIST_HEAD(&rtwvif_link->general_pkt_list);
|
||||
|
||||
rtw89_p2p_noa_once_init(rtwvif_link);
|
||||
|
|
@ -144,6 +146,7 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev,
|
|||
lockdep_assert_wiphy(rtwdev->hw->wiphy);
|
||||
|
||||
wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work);
|
||||
wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->csa_beacon_work);
|
||||
|
||||
rtw89_p2p_noa_once_deinit(rtwvif_link);
|
||||
|
||||
|
|
@ -1354,6 +1357,73 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx);
|
||||
}
|
||||
|
||||
static
|
||||
int rtw89_ops_switch_vif_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif_chanctx_switch *vifs,
|
||||
int n_vifs,
|
||||
enum ieee80211_chanctx_switch_mode mode)
|
||||
{
|
||||
struct rtw89_dev *rtwdev = hw->priv;
|
||||
bool replace;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
lockdep_assert_wiphy(hw->wiphy);
|
||||
|
||||
switch (mode) {
|
||||
case CHANCTX_SWMODE_REASSIGN_VIF:
|
||||
replace = false;
|
||||
break;
|
||||
case CHANCTX_SWMODE_SWAP_CONTEXTS:
|
||||
replace = true;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
struct ieee80211_vif_chanctx_switch *p = &vifs[i];
|
||||
struct ieee80211_bss_conf *link_conf = p->link_conf;
|
||||
struct rtw89_vif *rtwvif = vif_to_rtwvif(p->vif);
|
||||
struct rtw89_vif_link *rtwvif_link;
|
||||
|
||||
rtwvif_link = rtwvif->links[link_conf->link_id];
|
||||
if (unlikely(!rtwvif_link)) {
|
||||
rtw89_err(rtwdev,
|
||||
"%s: rtwvif link (link_id %u) is not active\n",
|
||||
__func__, link_conf->link_id);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
ret = rtw89_chanctx_ops_reassign_vif(rtwdev, rtwvif_link,
|
||||
p->old_ctx, p->new_ctx,
|
||||
replace);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtw89_ops_channel_switch_beacon(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
|
||||
struct rtw89_dev *rtwdev = hw->priv;
|
||||
struct rtw89_vif_link *rtwvif_link;
|
||||
|
||||
BUILD_BUG_ON(RTW89_MLD_NON_STA_LINK_NUM != 1);
|
||||
|
||||
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
|
||||
if (unlikely(!rtwvif_link)) {
|
||||
rtw89_err(rtwdev, "chsw bcn: find no link on HW-0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wiphy_delayed_work_queue(hw->wiphy, &rtwvif_link->csa_beacon_work, 0);
|
||||
}
|
||||
|
||||
static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan,
|
||||
|
|
@ -1805,6 +1875,8 @@ const struct ieee80211_ops rtw89_ops = {
|
|||
.change_chanctx = rtw89_ops_change_chanctx,
|
||||
.assign_vif_chanctx = rtw89_ops_assign_vif_chanctx,
|
||||
.unassign_vif_chanctx = rtw89_ops_unassign_vif_chanctx,
|
||||
.switch_vif_chanctx = rtw89_ops_switch_vif_chanctx,
|
||||
.channel_switch_beacon = rtw89_ops_channel_switch_beacon,
|
||||
.remain_on_channel = rtw89_ops_remain_on_channel,
|
||||
.cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel,
|
||||
.set_sar_specs = rtw89_ops_set_sar_specs,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user