]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: mld: update the TLC when we deactivate a link
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sat, 21 Mar 2026 17:29:16 +0000 (19:29 +0200)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 25 Mar 2026 09:31:58 +0000 (11:31 +0200)
We hit a problem in the channel switch flow.
We had link 0 using PHY 0, so the TLC object in the firmware is using
PHY 0.
Then we switched channel, so mac80211 / iwlmld:
* deactivated link 0
* removed PHY 0
* added PHY 1
* modified link 0 to use PHY 1
* activated link 0.

The TLC object was not updated and the firmware was unhappy that the TLC
was still trying to use PHY 0.

Fix that by letting the TLC know about the PHY context before the link
activation.
When we are de-activating a link, let the TLC know so that it'll send a
TLC configuration command with an invalid PHY context to remove the
relationship between the TLC object and the PHY that is going to be
removed.

That last part is not implemented yet in the firmware, so leave this as
a TODO for now.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260321192637.317c66b11a31.I591118fa376ed967c0d1a47058c13834bc94605e@changeid
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
drivers/net/wireless/intel/iwlwifi/mld/tlc.c
drivers/net/wireless/intel/iwlwifi/mld/tlc.h

index 8ab56788a49128c682952a21c96de2dc5095ed1d..9dec981a2bc59abf6fc5d72a3dc2dfb649524741 100644 (file)
@@ -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
         */
index ede385909e38f20eb480712e2ac727233e2dc2da..78d6162d9297efabebafb4946f6d5189de26a8c8 100644 (file)
@@ -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)
 {
index c32f42e8840bb2ef8a1fb57e368704f42cfd2555..c7ff209c9ab6660c77e0cdc1eb028219b5186dfa 100644 (file)
@@ -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__ */