diff options
author | Miri Korenblit <miriam.rachel.korenblit@intel.com> | 2024-02-25 21:20:52 +0200 |
---|---|---|
committer | iwlwifi publisher <> | 2024-04-17 13:03:53 +0000 |
commit | 3cde942a92edd729364513621ff94074d36f7d42 (patch) | |
tree | 525d95b4d0756a6674e5b4b0792c06181ffce7c6 | |
parent | f235968c8c117010aee6a6cf59de60de2c8eb7c4 (diff) | |
download | backport-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.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/link.c | 102 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 49 | ||||
-rw-r--r-- | versions | 2 |
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); +} @@ -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" |