@@ -253,28 +253,6 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm,
swap(data->primary, data->secondary);
}
-static void iwl_mvm_bt_coex_enable_esr(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif, bool enable)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- lockdep_assert_held(&mvm->mutex);
-
- if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
- return;
-
- /* Done already */
- if ((mvmvif->esr_disable_reason & IWL_MVM_ESR_DISABLE_COEX) == !enable)
- return;
-
- if (enable)
- mvmvif->esr_disable_reason &= ~IWL_MVM_ESR_DISABLE_COEX;
- else
- mvmvif->esr_disable_reason |= IWL_MVM_ESR_DISABLE_COEX;
-
- iwl_mvm_recalc_esr(mvm, vif);
-}
-
/*
* This function receives the LB link id and checks if eSR should be
* enabled or disabled (due to BT coex)
@@ -320,7 +298,7 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,
if (!link_rssi)
wifi_loss_rate = mvm->last_bt_notif.wifi_loss_mid_high_rssi;
- else if (!(mvmvif->esr_disable_reason & IWL_MVM_ESR_DISABLE_COEX))
+ else if (!(mvmvif->esr_disable_reason & IWL_MVM_ESR_BLOCKED_COEX))
/* RSSI needs to get really low to disable eSR... */
wifi_loss_rate =
link_rssi <= -IWL_MVM_BT_COEX_DISABLE_ESR_THRESH ?
@@ -348,7 +326,12 @@ void iwl_mvm_bt_coex_update_link_esr(struct iwl_mvm *mvm,
enable = iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link_id);
- iwl_mvm_bt_coex_enable_esr(mvm, vif, enable);
+ if (enable)
+ iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_COEX);
+ else
+ /* In case we decided to exit eSR - stay with the primary */
+ iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_COEX,
+ iwl_mvm_get_primary_link(vif));
}
static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm,
@@ -534,7 +517,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
/* When BT is off this will be 0 */
if (data->notif->wifi_loss_low_rssi == BT_OFF)
- iwl_mvm_bt_coex_enable_esr(mvm, vif, true);
+ iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_COEX);
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id);
@@ -560,7 +560,7 @@ bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
/* BT Coex effects eSR mode only if one of the link is on LB */
if (a->band == NL80211_BAND_2GHZ || b->band == NL80211_BAND_2GHZ)
- return !(mvmvif->esr_disable_reason & IWL_MVM_ESR_DISABLE_COEX);
+ return !(mvmvif->esr_disable_reason & IWL_MVM_ESR_BLOCKED_COEX);
return true;
}
@@ -691,3 +691,72 @@ u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif)
return __ffs(vif->active_links);
}
+
+/* API to exit eSR mode */
+void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum iwl_mvm_esr_state reason,
+ u8 link_to_keep)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u16 new_active_links;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* Nothing to do */
+ if (!mvmvif->esr_active)
+ return;
+
+ if (WARN_ON(!ieee80211_vif_is_mld(vif) || !mvmvif->authorized))
+ return;
+
+ if (WARN_ON(!(vif->active_links & BIT(link_to_keep))))
+ link_to_keep = __ffs(vif->active_links);
+
+ new_active_links = BIT(link_to_keep);
+ IWL_DEBUG_INFO(mvm,
+ "Exiting EMLSR. Reason = 0x%x. Current active links=0x%x, new active links = 0x%x\n",
+ reason, vif->active_links, new_active_links);
+
+ ieee80211_set_active_links_async(vif, new_active_links);
+}
+
+#define IWL_MVM_BLOCK_ESR_REASONS IWL_MVM_ESR_BLOCKED_COEX
+
+void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum iwl_mvm_esr_state reason,
+ u8 link_to_keep)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* This should be called only with disable reasons */
+ if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
+ return;
+
+ if (!(mvmvif->esr_disable_reason & reason))
+ IWL_DEBUG_INFO(mvm, "Blocking EMSLR mode. reason = 0x%x\n",
+ reason);
+
+ mvmvif->esr_disable_reason |= reason;
+
+ iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
+}
+
+void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum iwl_mvm_esr_state reason)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* This should be called only with disable reasons */
+ if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
+ return;
+
+ if (mvmvif->esr_disable_reason & reason)
+ IWL_DEBUG_INFO(mvm, "Unblocking EMSLR mode. reason = 0x%x\n",
+ reason);
+
+ mvmvif->esr_disable_reason &= ~reason;
+}
@@ -1151,28 +1151,6 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,
return ret;
}
-void iwl_mvm_recalc_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- bool enable = !mvmvif->esr_disable_reason;
- u16 new_active_links;
-
- /* Nothing to do */
- if (mvmvif->esr_active == enable)
- return;
-
- /* The next link selection will enter eSR if possible */
- if (enable)
- return;
-
- /*
- * Find the primary link, as we want to switch to it and drop the
- * secondary one.
- */
- new_active_links = BIT(iwl_mvm_get_primary_link(vif));
- ieee80211_set_active_links_async(vif, new_active_links);
-}
-
bool iwl_mvm_esr_allowed_on_vif(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
@@ -1194,7 +1172,7 @@ bool iwl_mvm_esr_allowed_on_vif(struct iwl_mvm *mvm,
!(ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP))
return false;
- return !(mvmvif->esr_disable_reason & ~IWL_MVM_ESR_DISABLE_COEX);
+ return !(mvmvif->esr_disable_reason & ~IWL_MVM_ESR_BLOCKED_COEX);
}
/*
@@ -346,11 +346,17 @@ struct iwl_mvm_vif_link_info {
};
/**
- * enum iwl_mvm_esr_disable_reason - reasons for which we can't enable EMLSR
- * @IWL_MVM_ESR_DISABLE_COEX: COEX is preventing the enablement of EMLSR
+ * enum iwl_mvm_esr_state - defines reasons for which the EMLSR is exited or
+ * blocked.
+ * The low 16 bits are used for blocking reasons, and the 16 higher bits
+ * are used for exit reasons.
+ * For the blocking reasons - use iwl_mvm_(un)block_esr(), and for the exit
+ * reasons - use iwl_mvm_exit_esr().
+ *
+ * @IWL_MVM_ESR_BLOCKED_COEX: COEX is preventing the enablement of EMLSR
*/
-enum iwl_mvm_esr_disable_reason {
- IWL_MVM_ESR_DISABLE_COEX = BIT(0),
+enum iwl_mvm_esr_state {
+ IWL_MVM_ESR_BLOCKED_COEX = 0x1,
};
/**
@@ -386,7 +392,7 @@ enum iwl_mvm_esr_disable_reason {
* @deflink: default link data for use in non-MLO
* @link: link data for each link in MLO
* @esr_active: indicates eSR mode is active
- * @esr_disable_reason: a bitmap of enum iwl_mvm_esr_disable_reason
+ * @esr_disable_reason: a bitmap of &enum iwl_mvm_esr_state
* @pm_enabled: indicates powersave is enabled
* @link_selection_res: bitmap of active links as it was decided in the last
* link selection. Valid only for a MLO vif after assoc. 0 if there wasn't
@@ -2836,8 +2842,15 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm,
int duration, u32 activity);
/* EMLSR */
-void iwl_mvm_recalc_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
bool iwl_mvm_esr_allowed_on_vif(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
+void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum iwl_mvm_esr_state reason,
+ u8 link_to_keep);
+void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum iwl_mvm_esr_state reason);
+void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum iwl_mvm_esr_state reason,
+ u8 link_to_keep);
#endif /* __IWL_MVM_H__ */