wifi: iwlwifi: mld: track channel_load_not_by_us
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Sun, 9 Mar 2025 05:36:41 +0000 (07:36 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 11 Mar 2025 15:29:24 +0000 (16:29 +0100)
For each channel context, track the avarage channel load by others in the
driver specific phy data, to be used by EMLSR.
Due to FW limitations, this value is incorrect in EMLSR, so it is
shouldn't be used in EMLSR.
On EMLSR exit, clear it so the wrong value won't be used.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Link: https://patch.msgid.link/20250309073442.dd443fc5b178.I68b2fed197aae14888159b7a73bf40c2f346f41f@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
drivers/net/wireless/intel/iwlwifi/mld/mlo.c
drivers/net/wireless/intel/iwlwifi/mld/phy.h
drivers/net/wireless/intel/iwlwifi/mld/stats.c
drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c

index ba149581e25d4f7312baeba9e4880b023ec5b4be..b01a41f9b01331232864ec1086023cbdffed5241 100644 (file)
@@ -847,6 +847,7 @@ int iwl_mld_add_chanctx(struct ieee80211_hw *hw,
        if (fw_id < 0)
                return fw_id;
 
+       phy->mld = mld;
        phy->fw_id = fw_id;
        phy->chandef = *iwl_mld_get_chandef_from_chanctx(ctx);
 
index 99c8501129b8f1f6064602092269edc94b093797..b68092be9aed7a20e9c0314b30ffa870e706a334 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2024-2025 Intel Corporation
  */
 #include "mlo.h"
+#include "phy.h"
 
 /* Block reasons helper */
 #define HANDLE_EMLSR_BLOCKED_REASONS(HOW)      \
@@ -177,6 +178,19 @@ static void iwl_mld_check_emlsr_prevention(struct iwl_mld *mld,
                                 &mld_vif->emlsr.prevent_done_wk, delay);
 }
 
+static void iwl_mld_clear_avg_chan_load_iter(struct ieee80211_hw *hw,
+                                            struct ieee80211_chanctx_conf *ctx,
+                                            void *dat)
+{
+       struct iwl_mld_phy *phy = iwl_mld_phy_from_mac80211(ctx);
+
+       /* It is ok to do it for all chanctx (and not only for the ones that
+        * belong to the EMLSR vif) since EMLSR is not allowed if there is
+        * another vif.
+        */
+       phy->avg_channel_load_not_by_us = 0;
+}
+
 static int _iwl_mld_exit_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif,
                               enum iwl_mld_emlsr_exit exit, u8 link_to_keep,
                               bool sync)
@@ -215,6 +229,13 @@ static int _iwl_mld_exit_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif,
        /* Update latest exit reason and check EMLSR prevention */
        iwl_mld_check_emlsr_prevention(mld, mld_vif, exit);
 
+       /* channel_load_not_by_us is invalid when in EMLSR.
+        * Clear it so wrong values won't be used.
+        */
+       ieee80211_iter_chan_contexts_atomic(mld->hw,
+                                           iwl_mld_clear_avg_chan_load_iter,
+                                           NULL);
+
        return ret;
 }
 
index 3dfb8ca994e2ed7f19e34a97254db53c2d9ce5a3..357bc9fe962498d95d03789524028dbf2c661ded 100644 (file)
@@ -15,6 +15,9 @@
  *     with. Used to detect a no-op when the chanctx changes.
  * @channel_load_by_us: channel load on this channel caused by
  *     the NIC itself, as indicated by firmware
+ * @avg_channel_load_not_by_us: averaged channel load on this channel caused by
+ *     others. This value is invalid when in EMLSR (due to FW limitations)
+ * @mld: pointer to the MLD context
  */
 struct iwl_mld_phy {
        /* Add here fields that need clean up on hw restart */
@@ -24,6 +27,8 @@ struct iwl_mld_phy {
        );
        /* And here fields that survive a hw restart */
        u32 channel_load_by_us;
+       u32 avg_channel_load_not_by_us;
+       struct iwl_mld *mld;
 };
 
 static inline struct iwl_mld_phy *
index 842b9b9fdd8c71e952a8f24adef8c9f698768fbb..5633885c49ff2ea1690b2a2b4102fc21fc82c76a 100644 (file)
@@ -461,6 +461,7 @@ static void iwl_mld_fill_chanctx_stats(struct ieee80211_hw *hw,
 {
        struct iwl_mld_phy *phy = iwl_mld_phy_from_mac80211(ctx);
        const struct iwl_stats_ntfy_per_phy *per_phy = data;
+       u32 new_load;
 
        if (WARN_ON(phy->fw_id >= IWL_STATS_MAX_PHY_OPERATIONAL))
                return;
@@ -468,7 +469,14 @@ static void iwl_mld_fill_chanctx_stats(struct ieee80211_hw *hw,
        phy->channel_load_by_us =
                le32_to_cpu(per_phy[phy->fw_id].channel_load_by_us);
 
-       /* TODO: channel load not by us (task=statistics) */
+       new_load = le32_to_cpu(per_phy[phy->fw_id].channel_load_not_by_us);
+       if (IWL_FW_CHECK(phy->mld, new_load > 100, "Invalid channel load %u\n",
+                        new_load))
+               return;
+
+       /* give a weight of 0.5 for the old value */
+       phy->avg_channel_load_not_by_us =
+               (new_load >> 1) + (phy->avg_channel_load_not_by_us >> 1);
 }
 
 static void
index a8c1e6c72138843fb6bf2f620c6330202078a606..b6049918b5dba2e5cf79920dd22e1c5a872509d2 100644 (file)
@@ -168,6 +168,7 @@ iwlmld_kunit_add_chanctx_from_def(struct cfg80211_chan_def *def)
        KUNIT_ASSERT_GE(test, fw_id, 0);
 
        phy->fw_id = fw_id;
+       phy->mld = mld;
        phy->chandef = *iwl_mld_get_chandef_from_chanctx(ctx);
 
        return ctx;