Commit 492bc4e4 authored by Miri Korenblit's avatar Miri Korenblit Committed by Johannes Berg

wifi: iwlwifi: mvm: implement EMLSR prevention mechanism.

Address scenarios where repeated entry and exit from EMLSR occur, such as
encountering missed beacons on a specific link,
while still discovering that link during a scan.

To mitigate this, introduce the EMLSR prevention mechanism, which operates
as follows:
- On each exit from EMLSR event, record the timestamp and the exit
  reason.
- If two consecutive exits happen for the same reason within a
  400-second window, enforce a 300-second EMLSR prevention.
- If a third exit for the same reason occurs within 400 seconds from the
  second exit, enforce an extended EMLSR prevention of 600 seconds.
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Link: https://msgid.link/20240416134215.d820ee98b300.I6406db40cf25eabdba602afd783466473b909216@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 48ac6c8e
......@@ -712,6 +712,55 @@ u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id)
}
}
/* Reasons that can cause esr prevention */
#define IWL_MVM_ESR_PREVENT_REASONS IWL_MVM_ESR_EXIT_MISSED_BEACON
#define IWL_MVM_PREVENT_ESR_TIMEOUT (HZ * 400)
#define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300)
#define IWL_MVM_ESR_PREVENT_LONG (HZ * 600)
static void iwl_mvm_recalc_esr_prevention(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif,
enum iwl_mvm_esr_state reason)
{
unsigned long now = jiffies;
unsigned long delay;
bool timeout_expired =
time_after(now, mvmvif->last_esr_exit.ts +
IWL_MVM_PREVENT_ESR_TIMEOUT);
if (WARN_ON(!(IWL_MVM_ESR_PREVENT_REASONS & reason)))
return;
lockdep_assert_held(&mvm->mutex);
mvmvif->last_esr_exit.ts = now;
if (timeout_expired ||
mvmvif->last_esr_exit.reason != reason) {
mvmvif->last_esr_exit.reason = reason;
mvmvif->exit_same_reason_count = 1;
return;
}
mvmvif->exit_same_reason_count++;
if (WARN_ON(mvmvif->exit_same_reason_count < 2 ||
mvmvif->exit_same_reason_count > 3))
return;
mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION;
delay = mvmvif->exit_same_reason_count == 2 ?
IWL_MVM_ESR_PREVENT_SHORT :
IWL_MVM_ESR_PREVENT_LONG;
IWL_DEBUG_INFO(mvm,
"Preventing EMLSR for %ld seconds due to %u exits with the reason 0x%x\n",
delay / HZ, mvmvif->exit_same_reason_count, reason);
wiphy_delayed_work_queue(mvm->hw->wiphy,
&mvmvif->prevent_esr_done_wk, delay);
}
/* API to exit eSR mode */
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_esr_state reason,
......@@ -738,6 +787,9 @@ void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
reason, vif->active_links, new_active_links);
ieee80211_set_active_links_async(vif, new_active_links);
if (IWL_MVM_ESR_PREVENT_REASONS & reason)
iwl_mvm_recalc_esr_prevention(mvm, mvmvif, reason);
}
void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
......
......@@ -1612,6 +1612,19 @@ static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm,
IWL_STA_MULTICAST);
}
static void iwl_mvm_prevent_esr_done_wk(struct wiphy *wiphy,
struct wiphy_work *wk)
{
struct iwl_mvm_vif *mvmvif =
container_of(wk, struct iwl_mvm_vif, prevent_esr_done_wk.work);
struct iwl_mvm *mvm = mvmvif->mvm;
struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm);
mutex_lock(&mvm->mutex);
iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_PREVENTION);
mutex_unlock(&mvm->mutex);
}
void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)
{
lockdep_assert_held(&mvm->mutex);
......@@ -1621,6 +1634,9 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)
INIT_DELAYED_WORK(&mvmvif->csa_work,
iwl_mvm_channel_switch_disconnect_wk);
wiphy_delayed_work_init(&mvmvif->prevent_esr_done_wk,
iwl_mvm_prevent_esr_done_wk);
}
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
......@@ -1764,6 +1780,9 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
flush_work(&mvm->roc_done_wk);
}
wiphy_delayed_work_cancel(mvm->hw->wiphy,
&mvmvif->prevent_esr_done_wk);
cancel_delayed_work_sync(&mvmvif->csa_work);
}
......@@ -3906,6 +3925,9 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
callbacks->mac_ctxt_changed(mvm, vif, false);
iwl_mvm_mei_host_associated(mvm, vif, mvm_sta);
memset(&mvmvif->last_esr_exit, 0,
sizeof(mvmvif->last_esr_exit));
/* Calculate eSR mode due to BT coex */
iwl_mvm_bt_coex_update_vif_esr(mvm, vif);
......@@ -3962,6 +3984,9 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
/* disable beacon filtering */
iwl_mvm_disable_beacon_filter(mvm, vif);
wiphy_delayed_work_cancel(mvm->hw->wiphy,
&mvmvif->prevent_esr_done_wk);
}
return 0;
......
......@@ -354,15 +354,29 @@ struct iwl_mvm_vif_link_info {
* reasons - use iwl_mvm_exit_esr().
*
* @IWL_MVM_ESR_BLOCKED_COEX: COEX is preventing the enablement of EMLSR
* @IWL_MVM_ESR_BLOCKED_PREVENTION: Prevent EMLSR to avoid entering and exiting
* in a loop.
* @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons
*/
enum iwl_mvm_esr_state {
IWL_MVM_ESR_BLOCKED_COEX = 0x1,
IWL_MVM_ESR_BLOCKED_PREVENTION = 0x2,
IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000,
};
#define IWL_MVM_BLOCK_ESR_REASONS 0xffff
/**
* struct iwl_mvm_esr_exit - details of the last exit from EMLSR mode.
* @reason: The reason for the last exit from EMLSR.
* &iwl_mvm_prevent_esr_reasons. Will be 0 before exiting EMLSR.
* @ts: the time stamp of the last time we existed EMLSR.
*/
struct iwl_mvm_esr_exit {
unsigned long ts;
enum iwl_mvm_esr_state reason;
};
/**
* struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
* @mvm: pointer back to the mvm struct
......@@ -404,6 +418,11 @@ enum iwl_mvm_esr_state {
* @link_selection_primary: primary link selected by link selection
* @primary_link: primary link in eSR. Valid only for an associated MLD vif,
* and in eSR mode. Valid only for a STA.
* @last_esr_exit: Details of the last exit from EMLSR.
* @exit_same_reason_count: The number of times we exited due to the specified
* @last_esr_exit::reason, only counting exits due to
* &IWL_MVM_ESR_PREVENT_REASONS.
* @prevent_esr_done_wk: work that should be done when esr prevention ends.
*/
struct iwl_mvm_vif {
struct iwl_mvm *mvm;
......@@ -497,6 +516,10 @@ struct iwl_mvm_vif {
u16 link_selection_res;
u8 link_selection_primary;
u8 primary_link;
struct iwl_mvm_esr_exit last_esr_exit;
u8 exit_same_reason_count;
struct wiphy_delayed_work prevent_esr_done_wk;
struct iwl_mvm_vif_link_info deflink;
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment