Skip to content

Commit 2f876f9

Browse files
committed
wifi: iwlwifi: mvm: exit EMLSR when CSA happens
If CSA is happening, then exit EMLSR to keep the better link, which is the primary link unless that's doing the CSA with quiet. This is done because we can't transmit the OMN frame on a quiet link, but want to exit EMLSR during CSA for better beacon reception, so we can follow the switch accurately. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://msgid.link/20240505091420.3ffff9577f08.I2620971fa5aef789e0d4a588def4c2621e8bed5b@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent ae7fe56 commit 2f876f9

5 files changed

Lines changed: 115 additions & 26 deletions

File tree

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,15 @@ iwl_mvm_esr_disallowed_with_link(struct ieee80211_vif *vif,
597597
{
598598
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
599599
struct iwl_mvm *mvm = mvmvif->mvm;
600+
struct wiphy *wiphy = mvm->hw->wiphy;
601+
struct ieee80211_bss_conf *conf;
600602
enum iwl_mvm_esr_state ret = 0;
601603
s8 thresh;
602604

605+
conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]);
606+
if (WARN_ON_ONCE(!conf))
607+
return false;
608+
603609
/* BT Coex effects eSR mode only if one of the links is on LB */
604610
if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
605611
(!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link->signal,
@@ -612,6 +618,9 @@ iwl_mvm_esr_disallowed_with_link(struct ieee80211_vif *vif,
612618
if (link->signal < thresh)
613619
ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
614620

621+
if (conf->csa_active)
622+
ret |= IWL_MVM_ESR_EXIT_CSA;
623+
615624
if (ret)
616625
IWL_DEBUG_INFO(mvm,
617626
"Link %d is not allowed for esr. Reason: 0x%x\n",

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

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5570,17 +5570,16 @@ static void iwl_mvm_csa_block_txqs(void *data, struct ieee80211_sta *sta)
55705570
}
55715571

55725572
#define IWL_MAX_CSA_BLOCK_TX 1500
5573-
int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
5573+
int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,
55745574
struct ieee80211_vif *vif,
55755575
struct ieee80211_channel_switch *chsw)
55765576
{
5577-
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
55785577
struct ieee80211_vif *csa_vif;
55795578
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
55805579
struct iwl_mvm_txq *mvmtxq;
55815580
int ret;
55825581

5583-
mutex_lock(&mvm->mutex);
5582+
lockdep_assert_held(&mvm->mutex);
55845583

55855584
mvmvif->csa_failed = false;
55865585
mvmvif->csa_blocks_tx = false;
@@ -5598,25 +5597,19 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
55985597
rcu_dereference_protected(mvm->csa_vif,
55995598
lockdep_is_held(&mvm->mutex));
56005599
if (WARN_ONCE(csa_vif && csa_vif->bss_conf.csa_active,
5601-
"Another CSA is already in progress")) {
5602-
ret = -EBUSY;
5603-
goto out_unlock;
5604-
}
5600+
"Another CSA is already in progress"))
5601+
return -EBUSY;
56055602

56065603
/* we still didn't unblock tx. prevent new CS meanwhile */
56075604
if (rcu_dereference_protected(mvm->csa_tx_blocked_vif,
5608-
lockdep_is_held(&mvm->mutex))) {
5609-
ret = -EBUSY;
5610-
goto out_unlock;
5611-
}
5605+
lockdep_is_held(&mvm->mutex)))
5606+
return -EBUSY;
56125607

56135608
rcu_assign_pointer(mvm->csa_vif, vif);
56145609

56155610
if (WARN_ONCE(mvmvif->csa_countdown,
5616-
"Previous CSA countdown didn't complete")) {
5617-
ret = -EBUSY;
5618-
goto out_unlock;
5619-
}
5611+
"Previous CSA countdown didn't complete"))
5612+
return -EBUSY;
56205613

56215614
mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;
56225615

@@ -5650,10 +5643,8 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
56505643
* we don't know the dtim period. In this case, the firmware can't
56515644
* track the beacons.
56525645
*/
5653-
if (!vif->cfg.assoc || !vif->bss_conf.dtim_period) {
5654-
ret = -EBUSY;
5655-
goto out_unlock;
5656-
}
5646+
if (!vif->cfg.assoc || !vif->bss_conf.dtim_period)
5647+
return -EBUSY;
56575648

56585649
if (chsw->delay > IWL_MAX_CSA_BLOCK_TX &&
56595650
hweight16(vif->valid_links) <= 1)
@@ -5675,7 +5666,7 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
56755666
IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {
56765667
ret = iwl_mvm_old_pre_chan_sw_sta(mvm, vif, chsw);
56775668
if (ret)
5678-
goto out_unlock;
5669+
return ret;
56795670
} else {
56805671
iwl_mvm_schedule_client_csa(mvm, vif, chsw);
56815672
}
@@ -5691,12 +5682,23 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
56915682

56925683
ret = iwl_mvm_power_update_ps(mvm);
56935684
if (ret)
5694-
goto out_unlock;
5685+
return ret;
56955686

56965687
/* we won't be on this channel any longer */
56975688
iwl_mvm_teardown_tdls_peers(mvm);
56985689

5699-
out_unlock:
5690+
return ret;
5691+
}
5692+
5693+
static int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw,
5694+
struct ieee80211_vif *vif,
5695+
struct ieee80211_channel_switch *chsw)
5696+
{
5697+
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
5698+
int ret;
5699+
5700+
mutex_lock(&mvm->mutex);
5701+
ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw);
57005702
mutex_unlock(&mvm->mutex);
57015703

57025704
return ret;
@@ -6482,7 +6484,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
64826484
.set_tim = iwl_mvm_set_tim,
64836485

64846486
.channel_switch = iwl_mvm_channel_switch,
6485-
.pre_channel_switch = iwl_mvm_pre_channel_switch,
6487+
.pre_channel_switch = iwl_mvm_mac_pre_channel_switch,
64866488
.post_channel_switch = iwl_mvm_post_channel_switch,
64876489
.abort_channel_switch = iwl_mvm_abort_channel_switch,
64886490
.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,

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

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,45 @@ iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
12901290
return NEG_TTLM_RES_ACCEPT;
12911291
}
12921292

1293+
static int
1294+
iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw,
1295+
struct ieee80211_vif *vif,
1296+
struct ieee80211_channel_switch *chsw)
1297+
{
1298+
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1299+
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1300+
int ret;
1301+
1302+
mutex_lock(&mvm->mutex);
1303+
if (mvmvif->esr_active) {
1304+
u8 primary = iwl_mvm_get_primary_link(vif);
1305+
int selected;
1306+
1307+
/* prefer primary unless quiet CSA on it */
1308+
if (chsw->link_id == primary && chsw->block_tx)
1309+
selected = iwl_mvm_get_other_link(vif, primary);
1310+
else
1311+
selected = primary;
1312+
1313+
iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_CSA, selected);
1314+
mutex_unlock(&mvm->mutex);
1315+
1316+
/*
1317+
* If we've not kept the link active that's doing the CSA
1318+
* then we don't need to do anything else, just return.
1319+
*/
1320+
if (selected != chsw->link_id)
1321+
return 0;
1322+
1323+
mutex_lock(&mvm->mutex);
1324+
}
1325+
1326+
ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw);
1327+
mutex_unlock(&mvm->mutex);
1328+
1329+
return ret;
1330+
}
1331+
12931332
const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
12941333
.tx = iwl_mvm_mac_tx,
12951334
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
@@ -1343,7 +1382,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
13431382
.tx_last_beacon = iwl_mvm_tx_last_beacon,
13441383

13451384
.channel_switch = iwl_mvm_channel_switch,
1346-
.pre_channel_switch = iwl_mvm_pre_channel_switch,
1385+
.pre_channel_switch = iwl_mvm_mld_mac_pre_channel_switch,
13471386
.post_channel_switch = iwl_mvm_post_channel_switch,
13481387
.abort_channel_switch = iwl_mvm_abort_channel_switch,
13491388
.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ struct iwl_mvm_vif_link_info {
365365
* due to BT Coex.
366366
* @IWL_MVM_ESR_EXIT_BANDWIDTH: Bandwidths of primary and secondry links
367367
* preventing the enablement of EMLSR
368+
* @IWL_MVM_ESR_EXIT_CSA: CSA happened, so exit EMLSR
368369
*/
369370
enum iwl_mvm_esr_state {
370371
IWL_MVM_ESR_BLOCKED_PREVENTION = 0x1,
@@ -375,6 +376,7 @@ enum iwl_mvm_esr_state {
375376
IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
376377
IWL_MVM_ESR_EXIT_COEX = 0x40000,
377378
IWL_MVM_ESR_EXIT_BANDWIDTH = 0x80000,
379+
IWL_MVM_ESR_EXIT_CSA = 0x100000,
378380
};
379381

380382
#define IWL_MVM_BLOCK_ESR_REASONS 0xffff
@@ -2818,7 +2820,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
28182820
int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw);
28192821
void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
28202822
struct ieee80211_channel_switch *chsw);
2821-
int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
2823+
int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,
28222824
struct ieee80211_vif *vif,
28232825
struct ieee80211_channel_switch *chsw);
28242826
void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,

drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010

1111
MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
1212

13+
static struct wiphy wiphy = {
14+
.mtx = __MUTEX_INITIALIZER(wiphy.mtx),
15+
};
16+
17+
static struct ieee80211_hw hw = {
18+
.wiphy = &wiphy,
19+
};
20+
1321
static struct ieee80211_channel chan_5ghz = {
1422
.band = NL80211_BAND_5GHZ,
1523
};
@@ -50,7 +58,10 @@ static struct iwl_fw fw = {
5058
},
5159
};
5260

53-
static struct iwl_mvm mvm = {.fw = &fw};
61+
static struct iwl_mvm mvm = {
62+
.hw = &hw,
63+
.fw = &fw,
64+
};
5465

5566
static const struct link_grading_case {
5667
const char *desc;
@@ -237,6 +248,7 @@ static const struct valid_link_pair_case {
237248
enum nl80211_chan_width cw_b;
238249
s32 sig_a;
239250
s32 sig_b;
251+
bool csa_a;
240252
bool valid;
241253
} valid_link_pair_cases[] = {
242254
{
@@ -335,6 +347,17 @@ static const struct valid_link_pair_case {
335347
.cw_b = NL80211_CHAN_WIDTH_160,
336348
.valid = true,
337349
},
350+
{
351+
.desc = "CSA active",
352+
.chan_a = &chan_6ghz,
353+
.cw_a = NL80211_CHAN_WIDTH_160,
354+
.sig_a = -5,
355+
.chan_b = &chan_5ghz,
356+
.cw_b = NL80211_CHAN_WIDTH_160,
357+
.valid = false,
358+
/* same as previous entry with valid=true except for CSA */
359+
.csa_a = true,
360+
},
338361
};
339362

340363
KUNIT_ARRAY_PARAM_DESC(valid_link_pair, valid_link_pair_cases, desc)
@@ -358,6 +381,7 @@ static void test_valid_link_pair(struct kunit *test)
358381
.link_id = 5,
359382
.signal = params->sig_b,
360383
};
384+
struct ieee80211_bss_conf *conf;
361385
bool result;
362386

363387
KUNIT_ASSERT_NOT_NULL(test, vif);
@@ -377,7 +401,20 @@ static void test_valid_link_pair(struct kunit *test)
377401
mvm.last_bt_notif.wifi_loss_low_rssi = params->bt;
378402
mvmvif->mvm = &mvm;
379403

404+
conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL);
405+
KUNIT_ASSERT_NOT_NULL(test, conf);
406+
conf->chanreq.oper = chandef_a;
407+
conf->csa_active = params->csa_a;
408+
vif->link_conf[link_a.link_id] = (void __rcu *)conf;
409+
410+
conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL);
411+
KUNIT_ASSERT_NOT_NULL(test, conf);
412+
conf->chanreq.oper = chandef_b;
413+
vif->link_conf[link_b.link_id] = (void __rcu *)conf;
414+
415+
wiphy_lock(&wiphy);
380416
result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b);
417+
wiphy_unlock(&wiphy);
381418

382419
KUNIT_EXPECT_EQ(test, result, params->valid);
383420

0 commit comments

Comments
 (0)