summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>2024-02-25 21:20:52 +0200
committeriwlwifi publisher <>2024-04-17 13:03:53 +0000
commit3cde942a92edd729364513621ff94074d36f7d42 (patch)
tree525d95b4d0756a6674e5b4b0792c06181ffce7c6
parentf235968c8c117010aee6a6cf59de60de2c8eb7c4 (diff)
downloadbackport-iwlwifi-3cde942a92edd729364513621ff94074d36f7d42.tar.gz
wifi: iwlwifi: mvm: trigger link selection after exiting EMLSR
If the reason for exiting EMLSR was a blocking reason, wait for the corresponding unblocking event: - if there is an ongoing scan - do nothing. Link selection will be triggered at the end of it. - If more than 30 seconds passed since the exit, trigger MLO scan, which will trigger link selection - If less then 30 seconds passed since exit, reuse the latest link selection result If the reason for exiting EMLSR was an exit reason (IWL_MVM_EXIT_*), schedule MLO scan in 30 seconds. type=feature ticket=jira:WIFI-387619 ticket=jira:WIFI-387615 Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Change-Id: Ia79605838eb6deee9358bec633ef537f2653db92 Reviewed-on: https://gerritwcs.ir.intel.com/c/iwlwifi-stack-dev/+/96234 tested: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Reviewed-by: Ilan Peer <ilan.peer@intel.com> x-iwlwifi-stack-dev: 3aaddae568ddb8a5586e8fc00d9c7e1a36cf9e24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/link.c102
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c49
-rw-r--r--versions2
8 files changed, 155 insertions, 52 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index a443121553..07f34908a9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -14,6 +14,7 @@
#define IWL_MVM_BT_COEX_DISABLE_ESR_THRESH 69
#define IWL_MVM_BT_COEX_ENABLE_ESR_THRESH 63
#define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH 0
+#define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30
#ifndef CPTCFG_IWLWIFI_SUPPORT_DEBUG_OVERRIDES
#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index b6e280187e..70d71b2ea2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -829,31 +829,7 @@ static ssize_t iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif *vif,
if (!action) {
ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false);
} else if (action == 1) {
- struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS];
- unsigned long usable_links = ieee80211_vif_usable_links(vif);
- size_t n_channels = 0;
- u8 link_id;
-
- rcu_read_lock();
-
- for_each_set_bit(link_id, &usable_links,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- struct ieee80211_bss_conf *link_conf =
- rcu_dereference(vif->link_conf[link_id]);
-
- if (WARN_ON_ONCE(!link_conf))
- continue;
-
- channels[n_channels++] = link_conf->chanreq.oper.chan;
- }
-
- rcu_read_unlock();
-
- if (n_channels)
- ret = iwl_mvm_int_mlo_scan_start(mvm, vif, channels,
- n_channels);
- else
- ret = -EINVAL;
+ ret = iwl_mvm_int_mlo_scan(mvm, vif);
} else {
ret = -EINVAL;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index 4968d97646..d031744971 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -784,37 +784,42 @@ u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id)
#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)
+static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm,
+ struct iwl_mvm_vif *mvmvif,
+ enum iwl_mvm_esr_state reason)
{
- unsigned long now = jiffies;
+ bool timeout_expired = time_after(jiffies,
+ mvmvif->last_esr_exit.ts +
+ IWL_MVM_PREVENT_ESR_TIMEOUT);
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;
+ /* Only handle reasons that can cause prevention */
+ if (!(reason & IWL_MVM_ESR_PREVENT_REASONS))
+ return false;
- if (timeout_expired ||
- mvmvif->last_esr_exit.reason != reason) {
- mvmvif->last_esr_exit.reason = reason;
+ /*
+ * Reset the counter if more than 400 seconds have passed between one
+ * exit and the other, or if we exited due to a different reason.
+ * Will also reset the counter after the long prevention is done.
+ */
+ if (timeout_expired || mvmvif->last_esr_exit.reason != reason) {
mvmvif->exit_same_reason_count = 1;
- return;
+ return false;
}
mvmvif->exit_same_reason_count++;
if (WARN_ON(mvmvif->exit_same_reason_count < 2 ||
mvmvif->exit_same_reason_count > 3))
- return;
+ return false;
mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION;
+ /*
+ * For the second exit, use a short prevention, and for the third one,
+ * use a long prevention.
+ */
delay = mvmvif->exit_same_reason_count == 2 ?
IWL_MVM_ESR_PREVENT_SHORT :
IWL_MVM_ESR_PREVENT_LONG;
@@ -825,8 +830,11 @@ static void iwl_mvm_recalc_esr_prevention(struct iwl_mvm *mvm,
wiphy_delayed_work_queue(mvm->hw->wiphy,
&mvmvif->prevent_esr_done_wk, delay);
+ return true;
}
+#define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ)
+
/* API to exit eSR mode */
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_esr_state reason,
@@ -834,6 +842,7 @@ void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u16 new_active_links;
+ bool prevented;
lockdep_assert_held(&mvm->mutex);
@@ -854,8 +863,25 @@ void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ieee80211_set_active_links_async(vif, new_active_links);
- if (IWL_MVM_ESR_PREVENT_REASONS & reason)
- iwl_mvm_recalc_esr_prevention(mvm, mvmvif, reason);
+ /* Prevent EMLSR if needed */
+ prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason);
+
+ /* Remember why and when we exited EMLSR */
+ mvmvif->last_esr_exit.ts = jiffies;
+ mvmvif->last_esr_exit.reason = reason;
+
+ /*
+ * If EMLSR is prevented now - don't try to get back to EMLSR.
+ * If we exited due to a blocking event, we will try to get back to
+ * EMLSR when the corresponding unblocking event will happen.
+ */
+ if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS)
+ return;
+
+ /* If EMLSR is not blocked - try enabling it again in 30 seconds */
+ wiphy_delayed_work_queue(mvm->hw->wiphy,
+ &mvmvif->mlo_int_scan_wk,
+ round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME));
}
void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -879,6 +905,43 @@ void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
}
+static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts +
+ IWL_MVM_TRIGGER_LINK_SEL_TIME);
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized ||
+ mvmvif->esr_active)
+ return;
+
+ IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n");
+
+ /*
+ * If EMLSR was blocked for more than 30 seconds, or the last link
+ * selection decided to not enter EMLSR, trigger a new scan.
+ */
+ if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) {
+ IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n");
+ wiphy_delayed_work_queue(mvm->hw->wiphy,
+ &mvmvif->mlo_int_scan_wk, 0);
+ /*
+ * If EMLSR was blocked for less than 30 seconds, and the last link
+ * selection decided to use EMLSR, activate EMLSR using the previous
+ * link selection result.
+ */
+ } else {
+ IWL_DEBUG_INFO(mvm,
+ "Use the latest link selection result: 0x%x\n",
+ mvmvif->link_selection_res);
+ ieee80211_set_active_links_async(vif,
+ mvmvif->link_selection_res);
+ }
+}
+
void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_esr_state reason)
{
@@ -895,4 +958,7 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
reason);
mvmvif->esr_disable_reason &= ~reason;
+
+ if (!mvmvif->esr_disable_reason)
+ iwl_mvm_esr_unblocked(mvm, vif);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index d4be674009..1b4e71ed28 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -4081,7 +4081,7 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
mvmvif->authorized = 1;
- mvmvif->link_selection_res = 0;
+ mvmvif->link_selection_res = vif->active_links;
callbacks->mac_ctxt_changed(mvm, vif, false);
iwl_mvm_mei_host_associated(mvm, vif, mvm_sta);
@@ -4149,6 +4149,9 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
wiphy_delayed_work_cancel(mvm->hw->wiphy,
&mvmvif->prevent_esr_done_wk);
+ wiphy_delayed_work_cancel(mvm->hw->wiphy,
+ &mvmvif->mlo_int_scan_wk);
+
/* No need for the periodic statistics anymore */
if (ieee80211_vif_is_mld(vif) && mvmvif->esr_active)
iwl_mvm_request_periodic_system_statistics(mvm, false);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 056f21fc62..391b05cd59 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -4,6 +4,20 @@
*/
#include "mvm.h"
+static void iwl_mvm_mlo_int_scan_wk(struct wiphy *wiphy, struct wiphy_work *wk)
+{
+ struct iwl_mvm_vif *mvmvif = container_of(wk, struct iwl_mvm_vif,
+ mlo_int_scan_wk.work);
+ struct ieee80211_vif *vif =
+ container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);
+
+ mutex_lock(&mvmvif->mvm->mutex);
+
+ iwl_mvm_int_mlo_scan(mvmvif->mvm, vif);
+
+ mutex_unlock(&mvmvif->mvm->mutex);
+}
+
static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -76,6 +90,8 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
iwl_mvm_tcm_add_vif(mvm, vif);
INIT_DELAYED_WORK(&mvmvif->csa_work,
iwl_mvm_channel_switch_disconnect_wk);
+ wiphy_delayed_work_init(&mvmvif->mlo_int_scan_wk,
+ iwl_mvm_mlo_int_scan_wk);
if (vif->type == NL80211_IFTYPE_MONITOR) {
mvm->monitor_on = true;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index a887ef632e..393eb70951 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -431,6 +431,7 @@ struct iwl_mvm_esr_exit {
* @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.
+ * @mlo_int_scan_wk: work for the internal MLO scan.
*/
struct iwl_mvm_vif {
struct iwl_mvm *mvm;
@@ -528,6 +529,7 @@ struct iwl_mvm_vif {
struct iwl_mvm_esr_exit last_esr_exit;
u8 exit_same_reason_count;
struct wiphy_delayed_work prevent_esr_done_wk;
+ struct wiphy_delayed_work mlo_int_scan_wk;
struct iwl_mvm_vif_link_info deflink;
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -2132,13 +2134,11 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_scan_ies *ies);
size_t iwl_mvm_scan_size(struct iwl_mvm *mvm);
int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify);
-int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_channel **channels,
- size_t n_channels);
int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
void iwl_mvm_scan_timeout_wk(struct work_struct *work);
+int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
/* Scheduled scan */
void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index bc7efb36cb..1497f4dc66 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -3113,6 +3113,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
struct iwl_umac_scan_complete *notif = (void *)pkt->data;
u32 uid = __le32_to_cpu(notif->uid);
bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);
+ bool select_links = false;
if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status)))
return;
@@ -3139,6 +3140,11 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_INT_MLO) {
IWL_DEBUG_SCAN(mvm, "Internal MLO scan completed\n");
+ /*
+ * Other scan types won't necessarily scan for the MLD links channels.
+ * Therefore, only select links after successful internal scan.
+ */
+ select_links = notif->status == IWL_SCAN_OFFLOAD_COMPLETED;
}
mvm->scan_status &= ~mvm->scan_uid_status[uid];
@@ -3159,7 +3165,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
mvm->scan_uid_status[uid] = 0;
- if (notif->status == IWL_SCAN_OFFLOAD_COMPLETED)
+ if (select_links)
iwl_mvm_post_scan_link_selection(mvm);
}
@@ -3421,9 +3427,10 @@ out:
return ret;
}
-int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_channel **channels,
- size_t n_channels)
+static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel **channels,
+ size_t n_channels)
{
struct cfg80211_scan_request *req = NULL;
struct ieee80211_scan_ies ies = {};
@@ -3467,3 +3474,37 @@ int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_DEBUG_SCAN(mvm, "Internal MLO scan: ret=%d\n", ret);
return ret;
}
+
+int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS];
+ unsigned long usable_links = ieee80211_vif_usable_links(vif);
+ size_t n_channels = 0;
+ u8 link_id;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (mvm->scan_status & IWL_MVM_SCAN_INT_MLO) {
+ IWL_DEBUG_SCAN(mvm, "Internal MLO scan is already running\n");
+ return -EBUSY;
+ }
+
+ rcu_read_lock();
+
+ for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct ieee80211_bss_conf *link_conf =
+ rcu_dereference(vif->link_conf[link_id]);
+
+ if (WARN_ON_ONCE(!link_conf))
+ continue;
+
+ channels[n_channels++] = link_conf->chanreq.oper.chan;
+ }
+
+ rcu_read_unlock();
+
+ if (!n_channels)
+ return -EINVAL;
+
+ return iwl_mvm_int_mlo_scan_start(mvm, vif, channels, n_channels);
+}
diff --git a/versions b/versions
index f6c0246124..17c33c0295 100644
--- a/versions
+++ b/versions
@@ -2,4 +2,4 @@ BACKPORTS_VERSION="(see git)"
BACKPORTED_KERNEL_VERSION="(see git)"
BACKPORTED_KERNEL_NAME="iwlwifi"
BACKPORTS_BUILD_TSTAMP=__DATE__ \" \" __TIME__
-BACKPORTS_GIT_TRACKED="iwlwifi-stack-public:master:11967:16f14248"
+BACKPORTS_GIT_TRACKED="iwlwifi-stack-public:master:11968:3aaddae5"