diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 9aa08d289680..a5c38f389c69 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -331,23 +331,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, if (ret) goto out; - /* Initialize rate control for the AP station, since we might be - * doing a link switch here - we cannot initialize it before since - * this needs the phy context assigned (and in FW?), and we cannot - * do it later because it needs to be initialized as soon as we're - * able to TX on the link, i.e. when active. + /* + * if link switching (link not active yet) we'll activate it in + * firmware later on link-info change, which mac80211 guarantees + * for link switch after the stations are set up */ - if (mvmvif->ap_sta) { - struct ieee80211_link_sta *link_sta; - - rcu_read_lock(); - link_sta = rcu_dereference(mvmvif->ap_sta->link[link_id]); - - if (!WARN_ON_ONCE(!link_sta)) - iwl_mvm_rs_rate_init(mvm, vif, mvmvif->ap_sta, - link_conf, link_sta, - phy_ctxt->channel->band); - rcu_read_unlock(); + if (ieee80211_vif_link_active(vif, link_conf->link_id)) { + ret = iwl_mvm_link_changed(mvm, vif, link_conf, + LINK_CONTEXT_MODIFY_ACTIVE | + LINK_CONTEXT_MODIFY_RATES_INFO, + true); + if (ret) + goto out; } if (vif->type == NL80211_IFTYPE_STATION) @@ -355,14 +350,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, link_conf, false); - /* then activate */ - ret = iwl_mvm_link_changed(mvm, vif, link_conf, - LINK_CONTEXT_MODIFY_ACTIVE | - LINK_CONTEXT_MODIFY_RATES_INFO, - true); - if (ret) - goto out; - /* * Power state must be updated before quotas, * otherwise fw will complain. @@ -775,6 +762,11 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id])) return; + /* not yet marked active in vif means during link switch */ + if (!ieee80211_vif_link_active(vif, link_conf->link_id) && + vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt) + link_changes |= LINK_CONTEXT_MODIFY_ACTIVE; + has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax; has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 28a9d90ad1cd..99eb1e1db1bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -1182,6 +1182,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, link_sta_added_to_fw |= BIT(link_id); iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link); + + iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta, + link_conf->chanreq.oper.chan->band); } if (sta_mask_added) { diff --git a/net/mac80211/link.c b/net/mac80211/link.c index 503bdea904bc..e8def387d0f8 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -388,6 +388,37 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, jiffies); } + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + + /* + * This call really should not fail. Unfortunately, it appears + * that this may happen occasionally with some drivers. Should + * it happen, we are stuck in a bad place as going backwards is + * not really feasible. + * + * So lets just tell link_use_channel that it must not fail to + * assign the channel context (from mac80211's perspective) and + * assume the driver is going to trigger a recovery flow if it + * had a failure. + * That really is not great nor guaranteed to work. But at least + * the internal mac80211 state remains consistent and there is + * a chance that we can recover. + */ + ret = _ieee80211_link_use_channel(link, + &link->conf->chanreq, + IEEE80211_CHANCTX_SHARED, + true); + WARN_ON_ONCE(ret); + + /* + * inform about the link info changed parameters after all + * stations are also added + */ + } + list_for_each_entry(sta, &local->sta_list, list) { if (sdata != sta->sdata) continue; @@ -431,26 +462,6 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, link = sdata_dereference(sdata->link[link_id], sdata); - /* - * This call really should not fail. Unfortunately, it appears - * that this may happen occasionally with some drivers. Should - * it happen, we are stuck in a bad place as going backwards is - * not really feasible. - * - * So lets just tell link_use_channel that it must not fail to - * assign the channel context (from mac80211's perspective) and - * assume the driver is going to trigger a recovery flow if it - * had a failure. - * That really is not great nor guaranteed to work. But at least - * the internal mac80211 state remains consistent and there is - * a chance that we can recover. - */ - ret = _ieee80211_link_use_channel(link, - &link->conf->chanreq, - IEEE80211_CHANCTX_SHARED, - true); - WARN_ON_ONCE(ret); - ieee80211_mgd_set_link_qos_params(link); ieee80211_link_info_change_notify(sdata, link, BSS_CHANGED_ERP_CTS_PROT |