]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: mld: allow EMLSR with 2.4 GHz when BT is ON
authorSomashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
Wed, 30 Apr 2025 12:23:15 +0000 (15:23 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 6 May 2025 17:23:02 +0000 (20:23 +0300)
When BT is ON, EMLSR with one of the links operating on 2.4 GHz
is allowed only if it meets following conditions.
In this patch:
1. during link selection, when BT is ON, allow emlsr only if BT
   pentalty is < 7%.
2. exit EMLSR if BT is turned ON and one of the links is operating
   on 2.4 GHz with BT penalty > 7%

Signed-off-by: Somashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250430151952.d30212ec3901.I48e3d5bd6b0b8583f98057c38d2ee30fff5abd8a@changeid
drivers/net/wireless/intel/iwlwifi/mld/coex.c
drivers/net/wireless/intel/iwlwifi/mld/mld.h
drivers/net/wireless/intel/iwlwifi/mld/mlo.c
drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c

index 5f262bd43f21d5882309817592616ac21eb2fb26..32c727b3b391a0d74f3aeb88a14394a7e23c2643 100644 (file)
@@ -24,17 +24,13 @@ int iwl_mld_send_bt_init_conf(struct iwl_mld *mld)
 void iwl_mld_handle_bt_coex_notif(struct iwl_mld *mld,
                                  struct iwl_rx_packet *pkt)
 {
-       const struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
+       const struct iwl_bt_coex_profile_notif *notif = (const void *)pkt->data;
        const struct iwl_bt_coex_profile_notif zero_notif = {};
        /* zeroed structure means that BT is OFF */
        bool bt_is_active = memcmp(notif, &zero_notif, sizeof(*notif));
 
-       if (bt_is_active == mld->bt_is_active)
-               return;
-
+       mld->last_bt_notif = *notif;
        IWL_DEBUG_INFO(mld, "BT was turned %s\n", bt_is_active ? "ON" : "OFF");
 
-       mld->bt_is_active = bt_is_active;
-
        iwl_mld_emlsr_check_bt(mld);
 }
index a4a16da6ebf3fbd63491849c6302db4ab35bc530..7007a43bca4ddb41dc81077a716888e73c61cbfc 100644 (file)
  *     cleanup using iwl_mld_free_internal_sta
  * @netdetect: indicates the FW is in suspend mode with netdetect configured
  * @p2p_device_vif: points to the p2p device vif if exists
- * @bt_is_active: indicates that BT is active
  * @dev: pointer to device struct. For printing purposes
  * @trans: pointer to the transport layer
  * @cfg: pointer to the device configuration
  * @ptp_data: data of the PTP clock
  * @time_sync: time sync data.
  * @ftm_initiator: FTM initiator data
+ * @last_bt_notif: last received BT Coex notif
  */
 struct iwl_mld {
        /* Add here fields that need clean up on restart */
@@ -207,7 +207,7 @@ struct iwl_mld {
                bool netdetect;
 #endif /* CONFIG_PM_SLEEP */
                struct ieee80211_vif *p2p_device_vif;
-               bool bt_is_active;
+               struct iwl_bt_coex_profile_notif last_bt_notif;
        );
        struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX];
        /* And here fields that survive a fw restart */
index 91f3a48d0c4b89bcde3723de8dae91cbcee1d76a..c84b39794c8fa435559156d5e256cf0ab313bc8a 100644 (file)
@@ -636,6 +636,40 @@ s8 iwl_mld_get_emlsr_rssi_thresh(struct iwl_mld *mld,
 #undef RSSI_THRESHOLD
 }
 
+#define IWL_MLD_BT_COEX_DISABLE_EMLSR_RSSI_THRESH      -69
+#define IWL_MLD_BT_COEX_ENABLE_EMLSR_RSSI_THRESH       -63
+#define IWL_MLD_BT_COEX_WIFI_LOSS_THRESH               7
+
+static bool
+iwl_mld_bt_allows_emlsr(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
+                       bool check_entry)
+{
+       int bt_penalty, rssi_thresh;
+       s32 link_rssi;
+
+       if (WARN_ON_ONCE(!link->bss))
+               return false;
+
+       link_rssi = MBM_TO_DBM(link->bss->signal);
+       rssi_thresh = check_entry ?
+                     IWL_MLD_BT_COEX_ENABLE_EMLSR_RSSI_THRESH :
+                     IWL_MLD_BT_COEX_DISABLE_EMLSR_RSSI_THRESH;
+       /* No valid RSSI - force to take low rssi */
+       if (!link_rssi)
+               link_rssi = rssi_thresh - 1;
+
+       if (link_rssi > rssi_thresh)
+               bt_penalty = max(mld->last_bt_notif.wifi_loss_mid_high_rssi[PHY_BAND_24][0],
+                                mld->last_bt_notif.wifi_loss_mid_high_rssi[PHY_BAND_24][1]);
+       else
+               bt_penalty = max(mld->last_bt_notif.wifi_loss_low_rssi[PHY_BAND_24][0],
+                                mld->last_bt_notif.wifi_loss_low_rssi[PHY_BAND_24][1]);
+
+       IWL_DEBUG_EHT(mld, "BT penalty for link-id %0X is %d\n",
+                     link->link_id, bt_penalty);
+       return bt_penalty < IWL_MLD_BT_COEX_WIFI_LOSS_THRESH;
+}
+
 static u32
 iwl_mld_emlsr_disallowed_with_link(struct iwl_mld *mld,
                                   struct ieee80211_vif *vif,
@@ -650,7 +684,8 @@ iwl_mld_emlsr_disallowed_with_link(struct iwl_mld *mld,
        if (WARN_ON_ONCE(!conf))
                return IWL_MLD_EMLSR_EXIT_INVALID;
 
-       if (link->chandef->chan->band == NL80211_BAND_2GHZ && mld->bt_is_active)
+       if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
+           !iwl_mld_bt_allows_emlsr(mld, conf, true))
                ret |= IWL_MLD_EMLSR_EXIT_BT_COEX;
 
        if (link->signal <
@@ -985,27 +1020,41 @@ static void iwl_mld_emlsr_check_bt_iter(void *_data, u8 *mac,
                                        struct ieee80211_vif *vif)
 {
        struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+       const struct iwl_bt_coex_profile_notif zero_notif = {};
        struct iwl_mld *mld = mld_vif->mld;
        struct ieee80211_bss_conf *link;
        unsigned int link_id;
+       const struct iwl_bt_coex_profile_notif *notif = &mld->last_bt_notif;
 
-       if (!mld->bt_is_active) {
-               iwl_mld_retry_emlsr(mld, vif);
+       if (!iwl_mld_vif_has_emlsr_cap(vif))
                return;
-       }
 
-       /* BT is turned ON but we are not in EMLSR, nothing to do */
-       if (!iwl_mld_emlsr_active(vif))
+       /* zeroed structure means that BT is OFF */
+       if (!memcmp(notif, &zero_notif, sizeof(*notif))) {
+               iwl_mld_retry_emlsr(mld, vif);
                return;
-
-       /* In EMLSR and BT is turned ON */
+       }
 
        for_each_vif_active_link(vif, link, link_id) {
+               bool emlsr_active, emlsr_allowed;
+
                if (WARN_ON(!link->chanreq.oper.chan))
                        continue;
 
-               if (link->chanreq.oper.chan->band == NL80211_BAND_2GHZ) {
-                       iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_BT_COEX,
+               if (link->chanreq.oper.chan->band != NL80211_BAND_2GHZ)
+                       continue;
+
+               emlsr_active = iwl_mld_emlsr_active(vif);
+               emlsr_allowed = iwl_mld_bt_allows_emlsr(mld, link,
+                                                       !emlsr_active);
+               if (emlsr_allowed && !emlsr_active) {
+                       iwl_mld_retry_emlsr(mld, vif);
+                       return;
+               }
+
+               if (!emlsr_allowed && emlsr_active) {
+                       iwl_mld_exit_emlsr(mld, vif,
+                                          IWL_MLD_EMLSR_EXIT_BT_COEX,
                                           iwl_mld_get_primary_link(vif));
                        return;
                }
index 766c24db36137b93294abf98cd60c69ee6828e60..94a037bec1fa8595f484e0daf53f5338938e468f 100644 (file)
@@ -287,6 +287,7 @@ static void test_iwl_mld_link_pair_allows_emlsr(struct kunit *test)
        const struct link_pair_case *params = test->param_value;
        struct iwl_mld *mld = test->priv;
        struct ieee80211_vif *vif;
+       struct ieee80211_bss_conf *link;
        /* link A is the primary and link B is the secondary */
        struct iwl_mld_link_sel_data a = {
                .chandef = params->chandef_a,
@@ -310,6 +311,11 @@ static void test_iwl_mld_link_pair_allows_emlsr(struct kunit *test)
 
        wiphy_lock(mld->wiphy);
 
+       link = wiphy_dereference(mld->wiphy, vif->link_conf[a.link_id]);
+       KUNIT_ALLOC_AND_ASSERT(test, link->bss);
+       link = wiphy_dereference(mld->wiphy, vif->link_conf[b.link_id]);
+       KUNIT_ALLOC_AND_ASSERT(test, link->bss);
+
        /* Simulate channel load */
        if (params->primary_link_active) {
                struct iwl_mld_phy *phy =