diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 8ab56788a491..9dec981a2bc5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -1148,6 +1148,8 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, /* Now activate the link */ if (iwl_mld_can_activate_link(mld, vif, link)) { + iwl_mld_tlc_update_phy(mld, vif, link); + ret = iwl_mld_activate_link(mld, link); if (ret) goto err; @@ -1209,6 +1211,8 @@ void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, RCU_INIT_POINTER(mld_link->chan_ctx, NULL); + iwl_mld_tlc_update_phy(mld, vif, link); + /* in the non-MLO case, remove/re-add the link to clean up FW state. * In MLO, it'll be done in drv_change_vif_link */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index ede385909e38..78d6162d9297 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -9,6 +9,7 @@ #include "hcmd.h" #include "sta.h" #include "phy.h" +#include "iface.h" #include "fw/api/rs.h" #include "fw/api/context.h" @@ -530,6 +531,7 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, struct ieee80211_bss_conf *link) { struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); + struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); enum nl80211_band band = link->chanreq.oper.chan->band; struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; const struct ieee80211_sta_he_cap *own_he_cap = @@ -566,7 +568,10 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id)); - chan_ctx = rcu_dereference_wiphy(mld->wiphy, link->chanctx_conf); + if (WARN_ON_ONCE(!mld_link)) + return; + + chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx); if (WARN_ON(!chan_ctx)) return; @@ -658,6 +663,49 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf); } +void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf); + struct ieee80211_chanctx_conf *chan_ctx; + int link_id = link_conf->link_id; + struct ieee80211_sta *sta; + + lockdep_assert_wiphy(mld->wiphy); + + if (WARN_ON(!mld_link)) + return; + + chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx); + + for_each_station(sta, mld->hw) { + struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); + struct iwl_mld_link_sta *mld_link_sta; + struct ieee80211_link_sta *link_sta; + + if (mld_sta->vif != vif) + continue; + + link_sta = link_sta_dereference_protected(sta, link_id); + if (!link_sta) + continue; + + mld_link_sta = iwl_mld_link_sta_dereference_check(mld_sta, + link_id); + + /* In recovery flow, the station may not be (yet) in the + * firmware, don't send a TLC command for a station the + * firmware does not know. + */ + if (!mld_link_sta || !mld_link_sta->in_fw) + continue; + + if (chan_ctx) + iwl_mld_config_tlc_link(mld, vif, link_conf, link_sta); + /* TODO: else, remove the TLC object in the firmware */ + } +} + void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.h b/drivers/net/wireless/intel/iwlwifi/mld/tlc.h index c32f42e8840b..c7ff209c9ab6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.h @@ -20,4 +20,7 @@ void iwl_mld_handle_tlc_notif(struct iwl_mld *mld, int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data); +void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); + #endif /* __iwl_mld_tlc_h__ */