mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
wifi: iwlwifi: mld: evacuate NAN channels on link switch
The FW API doesn't allow a station (of certain types, including STATION_TYPE_PEER) to not be correlated to any link. Therefore, when switching links, mac80211 first adds the new link and then removes the old one. In case we have a NAN interface that operates on 3 links and a BSS interface that operates on the 4th link, there won't be any room to perform a link switch that temporarily needs two links for the BSS interface, but the firmware only has four total. To mitigate this, try to evacuate a NAN channel in this scenario: First try to evacuate a NAN channel using the same phy as the BSS link being deactivated, since we expect NAN to follow the BSS channel configuration. If that doesn't work, try to evacuate any NAN channel. Reviewed-by: Johannes Berg <johannes.berg@intel.com> Link: https://patch.msgid.link/20260515150751.a193c0f41b1f.I1d56c8d8d61d110422271971843b71a93f5ec354@changeid Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
This commit is contained in:
parent
c024018744
commit
5aee72298c
|
|
@ -2585,15 +2585,108 @@ iwl_mld_mac80211_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
|||
ret);
|
||||
}
|
||||
|
||||
static int iwl_mld_count_free_link_ids(struct iwl_mld *mld)
|
||||
{
|
||||
int free_count = 0;
|
||||
|
||||
for (int i = 0; i < mld->fw->ucode_capa.num_links; i++) {
|
||||
if (!rcu_access_pointer(mld->fw_id_to_bss_conf[i]))
|
||||
free_count++;
|
||||
}
|
||||
|
||||
return free_count;
|
||||
}
|
||||
|
||||
static bool
|
||||
iwl_mld_chanctx_used_by_other_vif(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_chanctx_conf *chanctx_conf)
|
||||
{
|
||||
struct ieee80211_bss_conf *iter_link;
|
||||
struct ieee80211_vif *iter_vif;
|
||||
int link_id;
|
||||
|
||||
for_each_active_interface(iter_vif, hw) {
|
||||
if (vif == iter_vif)
|
||||
continue;
|
||||
|
||||
/* NAN doesn't have active links, so we don't count NAN users */
|
||||
for_each_vif_active_link(iter_vif, iter_link, link_id) {
|
||||
if (rcu_access_pointer(iter_link->chanctx_conf) ==
|
||||
chanctx_conf)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool iwl_mld_can_activate_links(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u16 desired_links)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
int n_links = hweight16(desired_links);
|
||||
int n_add = hweight16(desired_links & ~vif->active_links);
|
||||
unsigned long to_deactivate = vif->active_links & ~desired_links;
|
||||
int free_link_ids;
|
||||
int i;
|
||||
|
||||
/* Check if HW supports the wanted number of links */
|
||||
return n_links <= iwl_mld_max_active_links(mld, vif);
|
||||
if (n_links > iwl_mld_max_active_links(mld, vif))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* During link switch, mac80211 first adds the new links, then removes
|
||||
* the old ones. This means we temporarily need extra link objects
|
||||
* during the transition. Check if we have enough free link IDs.
|
||||
*/
|
||||
|
||||
free_link_ids = iwl_mld_count_free_link_ids(mld);
|
||||
|
||||
if (free_link_ids >= n_add)
|
||||
return true;
|
||||
|
||||
if (!mld->nan_device_vif)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Not enough free link IDs. First try to evacuate NAN from the
|
||||
* channel context of a link that is going to be deactivated.
|
||||
*/
|
||||
for_each_set_bit(i, &to_deactivate, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
|
||||
link_conf = link_conf_dereference_protected(vif, i);
|
||||
if (!link_conf)
|
||||
continue;
|
||||
|
||||
chanctx_conf = wiphy_dereference(mld->wiphy, link_conf->chanctx_conf);
|
||||
if (!chanctx_conf)
|
||||
continue;
|
||||
|
||||
if (iwl_mld_chanctx_used_by_other_vif(hw, vif, chanctx_conf))
|
||||
continue;
|
||||
|
||||
if (ieee80211_nan_try_evacuate(hw, chanctx_conf)) {
|
||||
free_link_ids = iwl_mld_count_free_link_ids(mld);
|
||||
/*
|
||||
* Evacuation of one channel should do the job. If not,
|
||||
* something bad is happening. Don't try to evacuate more
|
||||
*/
|
||||
return free_link_ids >= n_add;
|
||||
}
|
||||
}
|
||||
|
||||
/* Couldn't find/evacuate any channel going to go unused, try any */
|
||||
if (ieee80211_nan_try_evacuate(hw, NULL)) {
|
||||
free_link_ids = iwl_mld_count_free_link_ids(mld);
|
||||
if (free_link_ids >= n_add)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user