Skip to content

Commit 2f33561

Browse files
Miriam-Racheljmberg-intel
authored andcommitted
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. Signed-off-by: Miri Korenblit <[email protected]> Reviewed-by: Ilan Peer <[email protected]> Link: https://msgid.link/20240505091420.6a808c4ae8f5.Ia79605838eb6deee9358bec633ef537f2653db92@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 72c19df commit 2f33561

File tree

6 files changed

+158
-52
lines changed

6 files changed

+158
-52
lines changed

drivers/net/wireless/intel/iwlwifi/mvm/constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define IWL_MVM_BT_COEX_DISABLE_ESR_THRESH 69
1515
#define IWL_MVM_BT_COEX_ENABLE_ESR_THRESH 63
1616
#define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH 0
17+
#define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30
1718

1819
#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
1920
#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)

drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -712,31 +712,7 @@ static ssize_t iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif *vif,
712712
if (!action) {
713713
ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false);
714714
} else if (action == 1) {
715-
struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS];
716-
unsigned long usable_links = ieee80211_vif_usable_links(vif);
717-
size_t n_channels = 0;
718-
u8 link_id;
719-
720-
rcu_read_lock();
721-
722-
for_each_set_bit(link_id, &usable_links,
723-
IEEE80211_MLD_MAX_NUM_LINKS) {
724-
struct ieee80211_bss_conf *link_conf =
725-
rcu_dereference(vif->link_conf[link_id]);
726-
727-
if (WARN_ON_ONCE(!link_conf))
728-
continue;
729-
730-
channels[n_channels++] = link_conf->chanreq.oper.chan;
731-
}
732-
733-
rcu_read_unlock();
734-
735-
if (n_channels)
736-
ret = iwl_mvm_int_mlo_scan_start(mvm, vif, channels,
737-
n_channels);
738-
else
739-
ret = -EINVAL;
715+
ret = iwl_mvm_int_mlo_scan(mvm, vif);
740716
} else {
741717
ret = -EINVAL;
742718
}

drivers/net/wireless/intel/iwlwifi/mvm/link.c

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -787,37 +787,42 @@ u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id)
787787
#define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300)
788788
#define IWL_MVM_ESR_PREVENT_LONG (HZ * 600)
789789

790-
static void iwl_mvm_recalc_esr_prevention(struct iwl_mvm *mvm,
791-
struct iwl_mvm_vif *mvmvif,
792-
enum iwl_mvm_esr_state reason)
790+
static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm,
791+
struct iwl_mvm_vif *mvmvif,
792+
enum iwl_mvm_esr_state reason)
793793
{
794-
unsigned long now = jiffies;
794+
bool timeout_expired = time_after(jiffies,
795+
mvmvif->last_esr_exit.ts +
796+
IWL_MVM_PREVENT_ESR_TIMEOUT);
795797
unsigned long delay;
796-
bool timeout_expired =
797-
time_after(now, mvmvif->last_esr_exit.ts +
798-
IWL_MVM_PREVENT_ESR_TIMEOUT);
799-
800-
if (WARN_ON(!(IWL_MVM_ESR_PREVENT_REASONS & reason)))
801-
return;
802798

803799
lockdep_assert_held(&mvm->mutex);
804800

805-
mvmvif->last_esr_exit.ts = now;
801+
/* Only handle reasons that can cause prevention */
802+
if (!(reason & IWL_MVM_ESR_PREVENT_REASONS))
803+
return false;
806804

807-
if (timeout_expired ||
808-
mvmvif->last_esr_exit.reason != reason) {
809-
mvmvif->last_esr_exit.reason = reason;
805+
/*
806+
* Reset the counter if more than 400 seconds have passed between one
807+
* exit and the other, or if we exited due to a different reason.
808+
* Will also reset the counter after the long prevention is done.
809+
*/
810+
if (timeout_expired || mvmvif->last_esr_exit.reason != reason) {
810811
mvmvif->exit_same_reason_count = 1;
811-
return;
812+
return false;
812813
}
813814

814815
mvmvif->exit_same_reason_count++;
815816
if (WARN_ON(mvmvif->exit_same_reason_count < 2 ||
816817
mvmvif->exit_same_reason_count > 3))
817-
return;
818+
return false;
818819

819820
mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION;
820821

822+
/*
823+
* For the second exit, use a short prevention, and for the third one,
824+
* use a long prevention.
825+
*/
821826
delay = mvmvif->exit_same_reason_count == 2 ?
822827
IWL_MVM_ESR_PREVENT_SHORT :
823828
IWL_MVM_ESR_PREVENT_LONG;
@@ -828,15 +833,19 @@ static void iwl_mvm_recalc_esr_prevention(struct iwl_mvm *mvm,
828833

829834
wiphy_delayed_work_queue(mvm->hw->wiphy,
830835
&mvmvif->prevent_esr_done_wk, delay);
836+
return true;
831837
}
832838

839+
#define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ)
840+
833841
/* API to exit eSR mode */
834842
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
835843
enum iwl_mvm_esr_state reason,
836844
u8 link_to_keep)
837845
{
838846
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
839847
u16 new_active_links;
848+
bool prevented;
840849

841850
lockdep_assert_held(&mvm->mutex);
842851

@@ -857,8 +866,25 @@ void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
857866

858867
ieee80211_set_active_links_async(vif, new_active_links);
859868

860-
if (IWL_MVM_ESR_PREVENT_REASONS & reason)
861-
iwl_mvm_recalc_esr_prevention(mvm, mvmvif, reason);
869+
/* Prevent EMLSR if needed */
870+
prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason);
871+
872+
/* Remember why and when we exited EMLSR */
873+
mvmvif->last_esr_exit.ts = jiffies;
874+
mvmvif->last_esr_exit.reason = reason;
875+
876+
/*
877+
* If EMLSR is prevented now - don't try to get back to EMLSR.
878+
* If we exited due to a blocking event, we will try to get back to
879+
* EMLSR when the corresponding unblocking event will happen.
880+
*/
881+
if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS)
882+
return;
883+
884+
/* If EMLSR is not blocked - try enabling it again in 30 seconds */
885+
wiphy_delayed_work_queue(mvm->hw->wiphy,
886+
&mvmvif->mlo_int_scan_wk,
887+
round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME));
862888
}
863889

864890
void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -882,6 +908,43 @@ void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
882908
iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
883909
}
884910

911+
static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
912+
struct ieee80211_vif *vif)
913+
{
914+
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
915+
bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts +
916+
IWL_MVM_TRIGGER_LINK_SEL_TIME);
917+
918+
lockdep_assert_held(&mvm->mutex);
919+
920+
if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized ||
921+
mvmvif->esr_active)
922+
return;
923+
924+
IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n");
925+
926+
/*
927+
* If EMLSR was blocked for more than 30 seconds, or the last link
928+
* selection decided to not enter EMLSR, trigger a new scan.
929+
*/
930+
if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) {
931+
IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n");
932+
wiphy_delayed_work_queue(mvm->hw->wiphy,
933+
&mvmvif->mlo_int_scan_wk, 0);
934+
/*
935+
* If EMLSR was blocked for less than 30 seconds, and the last link
936+
* selection decided to use EMLSR, activate EMLSR using the previous
937+
* link selection result.
938+
*/
939+
} else {
940+
IWL_DEBUG_INFO(mvm,
941+
"Use the latest link selection result: 0x%x\n",
942+
mvmvif->link_selection_res);
943+
ieee80211_set_active_links_async(vif,
944+
mvmvif->link_selection_res);
945+
}
946+
}
947+
885948
void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
886949
enum iwl_mvm_esr_state reason)
887950
{
@@ -898,4 +961,7 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
898961
reason);
899962

900963
mvmvif->esr_disable_reason &= ~reason;
964+
965+
if (!mvmvif->esr_disable_reason)
966+
iwl_mvm_esr_unblocked(mvm, vif);
901967
}

drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,20 @@ static void iwl_mvm_prevent_esr_done_wk(struct wiphy *wiphy,
16251625
mutex_unlock(&mvm->mutex);
16261626
}
16271627

1628+
static void iwl_mvm_mlo_int_scan_wk(struct wiphy *wiphy, struct wiphy_work *wk)
1629+
{
1630+
struct iwl_mvm_vif *mvmvif = container_of(wk, struct iwl_mvm_vif,
1631+
mlo_int_scan_wk.work);
1632+
struct ieee80211_vif *vif =
1633+
container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);
1634+
1635+
mutex_lock(&mvmvif->mvm->mutex);
1636+
1637+
iwl_mvm_int_mlo_scan(mvmvif->mvm, vif);
1638+
1639+
mutex_unlock(&mvmvif->mvm->mutex);
1640+
}
1641+
16281642
void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)
16291643
{
16301644
lockdep_assert_held(&mvm->mutex);
@@ -1637,6 +1651,9 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)
16371651

16381652
wiphy_delayed_work_init(&mvmvif->prevent_esr_done_wk,
16391653
iwl_mvm_prevent_esr_done_wk);
1654+
1655+
wiphy_delayed_work_init(&mvmvif->mlo_int_scan_wk,
1656+
iwl_mvm_mlo_int_scan_wk);
16401657
}
16411658

16421659
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
@@ -1783,6 +1800,9 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
17831800
wiphy_delayed_work_cancel(mvm->hw->wiphy,
17841801
&mvmvif->prevent_esr_done_wk);
17851802

1803+
wiphy_delayed_work_cancel(mvm->hw->wiphy,
1804+
&mvmvif->mlo_int_scan_wk);
1805+
17861806
cancel_delayed_work_sync(&mvmvif->csa_work);
17871807
}
17881808

@@ -3877,7 +3897,6 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw,
38773897
return callbacks->update_sta(mvm, vif, sta);
38783898
}
38793899

3880-
38813900
static int
38823901
iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
38833902
struct ieee80211_vif *vif,
@@ -3901,7 +3920,7 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
39013920
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
39023921

39033922
mvmvif->authorized = 1;
3904-
mvmvif->link_selection_res = 0;
3923+
mvmvif->link_selection_res = vif->active_links;
39053924
mvmvif->link_selection_primary =
39063925
vif->active_links ? __ffs(vif->active_links) : 0;
39073926

@@ -3968,6 +3987,9 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
39683987
wiphy_delayed_work_cancel(mvm->hw->wiphy,
39693988
&mvmvif->prevent_esr_done_wk);
39703989

3990+
wiphy_delayed_work_cancel(mvm->hw->wiphy,
3991+
&mvmvif->mlo_int_scan_wk);
3992+
39713993
/* No need for the periodic statistics anymore */
39723994
if (ieee80211_vif_is_mld(vif) && mvmvif->esr_active)
39733995
iwl_mvm_request_periodic_system_statistics(mvm, false);

drivers/net/wireless/intel/iwlwifi/mvm/mvm.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ struct iwl_mvm_esr_exit {
429429
* @last_esr_exit::reason, only counting exits due to
430430
* &IWL_MVM_ESR_PREVENT_REASONS.
431431
* @prevent_esr_done_wk: work that should be done when esr prevention ends.
432+
* @mlo_int_scan_wk: work for the internal MLO scan.
432433
*/
433434
struct iwl_mvm_vif {
434435
struct iwl_mvm *mvm;
@@ -525,6 +526,7 @@ struct iwl_mvm_vif {
525526
struct iwl_mvm_esr_exit last_esr_exit;
526527
u8 exit_same_reason_count;
527528
struct wiphy_delayed_work prevent_esr_done_wk;
529+
struct wiphy_delayed_work mlo_int_scan_wk;
528530

529531
struct iwl_mvm_vif_link_info deflink;
530532
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -2089,13 +2091,11 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
20892091
struct ieee80211_scan_ies *ies);
20902092
size_t iwl_mvm_scan_size(struct iwl_mvm *mvm);
20912093
int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify);
2092-
int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
2093-
struct ieee80211_channel **channels,
2094-
size_t n_channels);
20952094

20962095
int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
20972096
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
20982097
void iwl_mvm_scan_timeout_wk(struct work_struct *work);
2098+
int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
20992099

21002100
/* Scheduled scan */
21012101
void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,

drivers/net/wireless/intel/iwlwifi/mvm/scan.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
32023202
struct iwl_umac_scan_complete *notif = (void *)pkt->data;
32033203
u32 uid = __le32_to_cpu(notif->uid);
32043204
bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);
3205+
bool select_links = false;
32053206

32063207
mvm->mei_scan_filter.is_mei_limited_scan = false;
32073208

@@ -3235,6 +3236,11 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
32353236
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
32363237
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_INT_MLO) {
32373238
IWL_DEBUG_SCAN(mvm, "Internal MLO scan completed\n");
3239+
/*
3240+
* Other scan types won't necessarily scan for the MLD links channels.
3241+
* Therefore, only select links after successful internal scan.
3242+
*/
3243+
select_links = notif->status == IWL_SCAN_OFFLOAD_COMPLETED;
32383244
}
32393245

32403246
mvm->scan_status &= ~mvm->scan_uid_status[uid];
@@ -3255,7 +3261,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
32553261

32563262
mvm->scan_uid_status[uid] = 0;
32573263

3258-
if (notif->status == IWL_SCAN_OFFLOAD_COMPLETED)
3264+
if (select_links)
32593265
iwl_mvm_post_scan_link_selection(mvm);
32603266
}
32613267

@@ -3517,9 +3523,10 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify)
35173523
return ret;
35183524
}
35193525

3520-
int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
3521-
struct ieee80211_channel **channels,
3522-
size_t n_channels)
3526+
static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm,
3527+
struct ieee80211_vif *vif,
3528+
struct ieee80211_channel **channels,
3529+
size_t n_channels)
35233530
{
35243531
struct cfg80211_scan_request *req = NULL;
35253532
struct ieee80211_scan_ies ies = {};
@@ -3563,3 +3570,37 @@ int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
35633570
IWL_DEBUG_SCAN(mvm, "Internal MLO scan: ret=%d\n", ret);
35643571
return ret;
35653572
}
3573+
3574+
int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
3575+
{
3576+
struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS];
3577+
unsigned long usable_links = ieee80211_vif_usable_links(vif);
3578+
size_t n_channels = 0;
3579+
u8 link_id;
3580+
3581+
lockdep_assert_held(&mvm->mutex);
3582+
3583+
if (mvm->scan_status & IWL_MVM_SCAN_INT_MLO) {
3584+
IWL_DEBUG_SCAN(mvm, "Internal MLO scan is already running\n");
3585+
return -EBUSY;
3586+
}
3587+
3588+
rcu_read_lock();
3589+
3590+
for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
3591+
struct ieee80211_bss_conf *link_conf =
3592+
rcu_dereference(vif->link_conf[link_id]);
3593+
3594+
if (WARN_ON_ONCE(!link_conf))
3595+
continue;
3596+
3597+
channels[n_channels++] = link_conf->chanreq.oper.chan;
3598+
}
3599+
3600+
rcu_read_unlock();
3601+
3602+
if (!n_channels)
3603+
return -EINVAL;
3604+
3605+
return iwl_mvm_int_mlo_scan_start(mvm, vif, channels, n_channels);
3606+
}

0 commit comments

Comments
 (0)