Skip to content

Commit a1efeb8

Browse files
yedidyaBenshjmberg-intel
authored andcommitted
wifi: iwlwifi: mvm: Block EMLSR when a p2p/softAP vif is active
When there's an active link in a non-station vif, the station vif is not allowed to enter EMLSR Note that blocking EMLSR by calling iwl_mvm_block_esr() we will schedule an exit from EMLSR worker, but the worker cannot run before the activation of the non-BSS link, as ieee80211_remain_on_channel already holds the wiphy mutex. Handle that by explicitly calling ieee80211_set_active_links() to leave EMLSR, and then doing iwl_mvm_block_esr() only for consistency and to avoid re-entering it before ready. Note that a call to ieee80211_set_active_links requires to release the mvm mutex, but that's ok since we still hold the wiphy lock. The only thing that might race here is the ESR_MODE_NOTIF, so this changes its handler to run under the wiphy lock. Signed-off-by: Yedidya Benshimol <yedidya.ben.shimol@intel.com> Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://msgid.link/20240505091420.916193759f8a.Idf3a3caf5cdc3e69c81710b7ceb57e87f2de87e4@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent eead359 commit a1efeb8

7 files changed

Lines changed: 133 additions & 19 deletions

File tree

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

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12431243
.data[0] = &d3_cfg_cmd_data,
12441244
.len[0] = sizeof(d3_cfg_cmd_data),
12451245
};
1246-
int ret, primary_link;
1246+
int ret;
12471247
int len __maybe_unused;
12481248
bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
12491249
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
@@ -1261,26 +1261,19 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12611261
if (IS_ERR_OR_NULL(vif))
12621262
return 1;
12631263

1264-
primary_link = iwl_mvm_get_primary_link(vif);
1265-
1266-
/* leave ESR immediately, not only async with iwl_mvm_block_esr() */
1267-
if (ieee80211_vif_is_mld(vif)) {
1268-
ret = ieee80211_set_active_links(vif, BIT(primary_link));
1269-
if (ret)
1270-
return ret;
1271-
}
1264+
ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN);
1265+
if (ret)
1266+
return ret;
12721267

12731268
mutex_lock(&mvm->mutex);
1274-
/* only additionally block for consistency and to avoid concurrency */
1275-
iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN, primary_link);
12761269

12771270
set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
12781271

12791272
synchronize_net();
12801273

12811274
mvmvif = iwl_mvm_vif_from_mac80211(vif);
12821275

1283-
mvm_link = mvmvif->link[primary_link];
1276+
mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)];
12841277
if (WARN_ON_ONCE(!mvm_link)) {
12851278
ret = -EINVAL;
12861279
goto out_noreset;

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,65 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
108108
return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
109109
}
110110

111+
struct iwl_mvm_esr_iter_data {
112+
struct ieee80211_vif *vif;
113+
unsigned int link_id;
114+
bool lift_block;
115+
};
116+
117+
static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac,
118+
struct ieee80211_vif *vif)
119+
{
120+
struct iwl_mvm_esr_iter_data *data = _data;
121+
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
122+
int link_id;
123+
124+
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
125+
return;
126+
127+
for_each_mvm_vif_valid_link(mvmvif, link_id) {
128+
struct iwl_mvm_vif_link_info *link_info =
129+
mvmvif->link[link_id];
130+
if (vif == data->vif && link_id == data->link_id)
131+
continue;
132+
if (link_info->active)
133+
data->lift_block = false;
134+
}
135+
}
136+
137+
int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
138+
unsigned int link_id, bool active)
139+
{
140+
/* An active link of a non-station vif blocks EMLSR. Upon activation
141+
* block EMLSR on the bss vif. Upon deactivation, check if this link
142+
* was the last non-station link active, and if so unblock the bss vif
143+
*/
144+
struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
145+
struct iwl_mvm_esr_iter_data data = {
146+
.vif = vif,
147+
.link_id = link_id,
148+
.lift_block = true,
149+
};
150+
151+
if (IS_ERR_OR_NULL(bss_vif))
152+
return 0;
153+
154+
if (active)
155+
return iwl_mvm_block_esr_sync(mvm, bss_vif,
156+
IWL_MVM_ESR_BLOCKED_NON_BSS);
157+
158+
ieee80211_iterate_active_interfaces(mvm->hw,
159+
IEEE80211_IFACE_ITER_NORMAL,
160+
iwl_mvm_esr_vif_iterator, &data);
161+
if (data.lift_block) {
162+
mutex_lock(&mvm->mutex);
163+
iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS);
164+
mutex_unlock(&mvm->mutex);
165+
}
166+
167+
return 0;
168+
}
169+
111170
int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
112171
struct ieee80211_bss_conf *link_conf,
113172
u32 changes, bool active)
@@ -924,6 +983,32 @@ void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
924983
iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
925984
}
926985

986+
int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
987+
enum iwl_mvm_esr_state reason)
988+
{
989+
int primary_link = iwl_mvm_get_primary_link(vif);
990+
int ret;
991+
992+
if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif))
993+
return 0;
994+
995+
/* This should be called only with blocking reasons */
996+
if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
997+
return 0;
998+
999+
/* leave ESR immediately, not only async with iwl_mvm_block_esr() */
1000+
ret = ieee80211_set_active_links(vif, BIT(primary_link));
1001+
if (ret)
1002+
return ret;
1003+
1004+
mutex_lock(&mvm->mutex);
1005+
/* only additionally block for consistency and to avoid concurrency */
1006+
iwl_mvm_block_esr(mvm, vif, reason, primary_link);
1007+
mutex_unlock(&mvm->mutex);
1008+
1009+
return 0;
1010+
}
1011+
9271012
static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
9281013
struct ieee80211_vif *vif)
9291014
{

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4830,6 +4830,10 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
48304830
*/
48314831
flush_work(&mvm->roc_done_wk);
48324832

4833+
ret = iwl_mvm_esr_non_bss_link(mvm, vif, 0, true);
4834+
if (ret)
4835+
return ret;
4836+
48334837
mutex_lock(&mvm->mutex);
48344838

48354839
switch (vif->type) {
@@ -4873,9 +4877,7 @@ int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
48734877

48744878
IWL_DEBUG_MAC80211(mvm, "enter\n");
48754879

4876-
mutex_lock(&mvm->mutex);
48774880
iwl_mvm_stop_roc(mvm, vif);
4878-
mutex_unlock(&mvm->mutex);
48794881

48804882
IWL_DEBUG_MAC80211(mvm, "leave\n");
48814883
return 0;

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,18 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
391391
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
392392
int ret;
393393

394+
/* update EMLSR mode */
395+
if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
396+
ret = iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id,
397+
true);
398+
/*
399+
* Don't activate this link if failed to exit EMLSR in
400+
* the BSS interface
401+
*/
402+
if (ret)
403+
return ret;
404+
}
405+
394406
mutex_lock(&mvm->mutex);
395407
ret = __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false);
396408
mutex_unlock(&mvm->mutex);
@@ -514,6 +526,10 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
514526
iwl_mvm_add_link(mvm, vif, link_conf);
515527
}
516528
mutex_unlock(&mvm->mutex);
529+
530+
/* update EMLSR mode */
531+
if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION)
532+
iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, false);
517533
}
518534

519535
static void

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ struct iwl_mvm_vif_link_info {
358358
* @IWL_MVM_ESR_BLOCKED_WOWLAN: WOWLAN is preventing the enablement of EMLSR
359359
* @IWL_MVM_ESR_BLOCKED_TPT: block EMLSR when there is not enough traffic
360360
* @IWL_MVM_ESR_BLOCKED_FW: FW didn't recommended/forced exit from EMLSR
361+
* @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-bssid link's preventing EMLSR
361362
* @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons
362363
* @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR
363364
* due to low RSSI.
@@ -372,6 +373,7 @@ enum iwl_mvm_esr_state {
372373
IWL_MVM_ESR_BLOCKED_WOWLAN = 0x2,
373374
IWL_MVM_ESR_BLOCKED_TPT = 0x4,
374375
IWL_MVM_ESR_BLOCKED_FW = 0x8,
376+
IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10,
375377
IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000,
376378
IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
377379
IWL_MVM_ESR_EXIT_COEX = 0x40000,
@@ -2888,6 +2890,8 @@ bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
28882890
void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
28892891
enum iwl_mvm_esr_state reason,
28902892
u8 link_to_keep);
2893+
int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
2894+
enum iwl_mvm_esr_state reason);
28912895
void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
28922896
enum iwl_mvm_esr_state reason);
28932897
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -2904,4 +2908,6 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,
29042908
struct ieee80211_vif *vif,
29052909
s32 link_rssi,
29062910
bool primary);
2911+
int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
2912+
unsigned int link_id, bool active);
29072913
#endif /* __IWL_MVM_H__ */

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
445445
struct iwl_channel_switch_error_notif),
446446

447447
RX_HANDLER_GRP(DATA_PATH_GROUP, ESR_MODE_NOTIF,
448-
iwl_mvm_rx_esr_mode_notif, RX_HANDLER_ASYNC_LOCKED,
448+
iwl_mvm_rx_esr_mode_notif,
449+
RX_HANDLER_ASYNC_LOCKED_WIPHY,
449450
struct iwl_mvm_esr_mode_notif),
450451

451452
RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,

drivers/net/wireless/intel/iwlwifi/mvm/time-event.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
4747

4848
static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
4949
{
50+
struct ieee80211_vif *vif = mvm->p2p_device_vif;
51+
52+
lockdep_assert_held(&mvm->mutex);
53+
5054
/*
5155
* Clear the ROC_RUNNING status bit.
5256
* This will cause the TX path to drop offchannel transmissions.
@@ -70,9 +74,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
7074
* not really racy.
7175
*/
7276

73-
if (!WARN_ON(!mvm->p2p_device_vif)) {
74-
struct ieee80211_vif *vif = mvm->p2p_device_vif;
75-
77+
if (!WARN_ON(!vif)) {
7678
mvmvif = iwl_mvm_vif_from_mac80211(vif);
7779
iwl_mvm_flush_sta(mvm, mvmvif->deflink.bcast_sta.sta_id,
7880
mvmvif->deflink.bcast_sta.tfd_queue_msk);
@@ -106,6 +108,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
106108

107109
if (mvm->mld_api_is_used) {
108110
iwl_mvm_mld_rm_aux_sta(mvm);
111+
mutex_unlock(&mvm->mutex);
109112
return;
110113
}
111114

@@ -115,15 +118,19 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
115118
if (iwl_mvm_has_new_station_api(mvm->fw))
116119
iwl_mvm_rm_aux_sta(mvm);
117120
}
121+
122+
mutex_unlock(&mvm->mutex);
123+
if (vif)
124+
iwl_mvm_esr_non_bss_link(mvm, vif, 0, false);
118125
}
119126

120127
void iwl_mvm_roc_done_wk(struct work_struct *wk)
121128
{
122129
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
123130

124131
mutex_lock(&mvm->mutex);
132+
/* Mutex is released inside */
125133
iwl_mvm_cleanup_roc(mvm);
126-
mutex_unlock(&mvm->mutex);
127134
}
128135

129136
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
@@ -1220,6 +1227,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
12201227
struct iwl_mvm_vif *mvmvif;
12211228
struct iwl_mvm_time_event_data *te_data;
12221229

1230+
mutex_lock(&mvm->mutex);
1231+
12231232
if (fw_has_capa(&mvm->fw->ucode_capa,
12241233
IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
12251234
mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -1263,6 +1272,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
12631272
set_bit(vif->type == NL80211_IFTYPE_P2P_DEVICE ?
12641273
IWL_MVM_STATUS_ROC_RUNNING : IWL_MVM_STATUS_ROC_AUX_RUNNING,
12651274
&mvm->status);
1275+
1276+
/* Mutex is released inside this function */
12661277
iwl_mvm_cleanup_roc(mvm);
12671278
}
12681279

0 commit comments

Comments
 (0)