summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2024-02-12 19:54:08 +0100
committeriwlwifi publisher <>2024-04-17 13:06:16 +0000
commitcc52697dfb227c0e48901d5c27081f9ea70d7f29 (patch)
tree62b2622a64a7caee566a304180744a8e8f375bd5
parent1d7c913bae381794e93b50688f67fffc34803c91 (diff)
downloadbackport-iwlwifi-cc52697dfb227c0e48901d5c27081f9ea70d7f29.tar.gz
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. type=feature ticket=jira:WIFI-379423 Change-Id: I2620971fa5aef789e0d4a588def4c2621e8bed5b Signed-off-by: Johannes Berg <johannes.berg@intel.com> Reviewed-on: https://gerritwcs.ir.intel.com/c/iwlwifi-stack-dev/+/94205 automatic-review: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM> tested: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM> Tested-by: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM> Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com> x-iwlwifi-stack-dev: bee758fa9d560fea001a7867e67943b9877be451
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/link.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c48
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c41
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c39
-rw-r--r--versions2
6 files changed, 116 insertions, 27 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index fa9d3ed4c0..2243f4ed10 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -597,9 +597,15 @@ iwl_mvm_esr_disallowed_with_link(struct ieee80211_vif *vif,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
+ struct wiphy *wiphy = mvm->hw->wiphy;
+ struct ieee80211_bss_conf *conf;
enum iwl_mvm_esr_state ret = 0;
s8 thresh;
+ conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]);
+ if (WARN_ON_ONCE(!conf))
+ return false;
+
/* BT Coex effects eSR mode only if one of the links is on LB */
if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
(!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,
if (link->signal < thresh)
ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
+ if (conf->csa_active)
+ ret |= IWL_MVM_ESR_EXIT_CSA;
+
if (ret)
IWL_DEBUG_INFO(mvm,
"Link %d is not allowed for esr. Reason: 0x%x\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index e99f6b7547..3f900e5bfd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -5760,17 +5760,16 @@ static void iwl_mvm_csa_block_txqs(void *data, struct ieee80211_sta *sta)
}
#define IWL_MAX_CSA_BLOCK_TX 1500
-int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
+int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct ieee80211_vif *csa_vif;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_txq *mvmtxq;
int ret;
- mutex_lock(&mvm->mutex);
+ lockdep_assert_held(&mvm->mutex);
mvmvif->csa_failed = false;
mvmvif->csa_blocks_tx = false;
@@ -5788,25 +5787,19 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
rcu_dereference_protected(mvm->csa_vif,
lockdep_is_held(&mvm->mutex));
if (WARN_ONCE(csa_vif && csa_vif->bss_conf.csa_active,
- "Another CSA is already in progress")) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ "Another CSA is already in progress"))
+ return -EBUSY;
/* we still didn't unblock tx. prevent new CS meanwhile */
if (rcu_dereference_protected(mvm->csa_tx_blocked_vif,
- lockdep_is_held(&mvm->mutex))) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ lockdep_is_held(&mvm->mutex)))
+ return -EBUSY;
rcu_assign_pointer(mvm->csa_vif, vif);
if (WARN_ONCE(mvmvif->csa_countdown,
- "Previous CSA countdown didn't complete")) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ "Previous CSA countdown didn't complete"))
+ return -EBUSY;
mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;
@@ -5840,10 +5833,8 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
* we don't know the dtim period. In this case, the firmware can't
* track the beacons.
*/
- if (!vif->cfg.assoc || !vif->bss_conf.dtim_period) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ if (!vif->cfg.assoc || !vif->bss_conf.dtim_period)
+ return -EBUSY;
if (chsw->delay > IWL_MAX_CSA_BLOCK_TX &&
hweight16(vif->valid_links) <= 1)
@@ -5865,7 +5856,7 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {
ret = iwl_mvm_old_pre_chan_sw_sta(mvm, vif, chsw);
if (ret)
- goto out_unlock;
+ return ret;
} else {
iwl_mvm_schedule_client_csa(mvm, vif, chsw);
}
@@ -5881,12 +5872,23 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
ret = iwl_mvm_power_update_ps(mvm);
if (ret)
- goto out_unlock;
+ return ret;
/* we won't be on this channel any longer */
iwl_mvm_teardown_tdls_peers(mvm);
-out_unlock:
+ return ret;
+}
+
+static int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *chsw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw);
mutex_unlock(&mvm->mutex);
return ret;
@@ -6671,7 +6673,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.set_tim = iwl_mvm_set_tim,
.channel_switch = iwl_mvm_channel_switch,
- .pre_channel_switch = iwl_mvm_pre_channel_switch,
+ .pre_channel_switch = iwl_mvm_mac_pre_channel_switch,
.post_channel_switch = iwl_mvm_post_channel_switch,
.abort_channel_switch = iwl_mvm_abort_channel_switch,
.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 06143eba1b..a4f92433fe 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -1306,6 +1306,45 @@ iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return NEG_TTLM_RES_ACCEPT;
}
+static int
+iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *chsw)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ if (mvmvif->esr_active) {
+ u8 primary = iwl_mvm_get_primary_link(vif);
+ int selected;
+
+ /* prefer primary unless quiet CSA on it */
+ if (chsw->link_id == primary && chsw->block_tx)
+ selected = iwl_mvm_get_other_link(vif, primary);
+ else
+ selected = primary;
+
+ iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_CSA, selected);
+ mutex_unlock(&mvm->mutex);
+
+ /*
+ * If we've not kept the link active that's doing the CSA
+ * then we don't need to do anything else, just return.
+ */
+ if (selected != chsw->link_id)
+ return 0;
+
+ mutex_lock(&mvm->mutex);
+ }
+
+ ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw);
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.tx = iwl_mvm_mac_tx,
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
@@ -1359,7 +1398,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.tx_last_beacon = iwl_mvm_tx_last_beacon,
.channel_switch = iwl_mvm_channel_switch,
- .pre_channel_switch = iwl_mvm_pre_channel_switch,
+ .pre_channel_switch = iwl_mvm_mld_mac_pre_channel_switch,
.post_channel_switch = iwl_mvm_post_channel_switch,
.abort_channel_switch = iwl_mvm_abort_channel_switch,
.channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 99a445616b..2f7036a80b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -367,6 +367,7 @@ struct iwl_mvm_vif_link_info {
* due to BT Coex.
* @IWL_MVM_ESR_EXIT_BANDWIDTH: Bandwidths of primary and secondry links
* preventing the enablement of EMLSR
+ * @IWL_MVM_ESR_EXIT_CSA: CSA happened, so exit EMLSR
*/
enum iwl_mvm_esr_state {
IWL_MVM_ESR_BLOCKED_PREVENTION = 0x1,
@@ -377,6 +378,7 @@ enum iwl_mvm_esr_state {
IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
IWL_MVM_ESR_EXIT_COEX = 0x40000,
IWL_MVM_ESR_EXIT_BANDWIDTH = 0x80000,
+ IWL_MVM_ESR_EXIT_CSA = 0x100000,
};
#define IWL_MVM_BLOCK_ESR_REASONS 0xffff
@@ -2870,7 +2872,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw);
void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw);
-int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
+int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw);
void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c
index 7382ce941a..d77494c365 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c
@@ -10,6 +10,14 @@
MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
+static struct wiphy wiphy = {
+ .mtx = __MUTEX_INITIALIZER(wiphy.mtx),
+};
+
+static struct ieee80211_hw hw = {
+ .wiphy = &wiphy,
+};
+
static struct ieee80211_channel chan_5ghz = {
.band = NL80211_BAND_5GHZ,
};
@@ -50,7 +58,10 @@ static const struct iwl_ucode_capabilities ucode_capa = {
static struct iwl_fw fw = {.ucode_capa = ucode_capa};
-static struct iwl_mvm mvm = {.fw = &fw};
+static struct iwl_mvm mvm = {
+ .hw = &hw,
+ .fw = &fw,
+};
static const struct link_grading_case {
const char *desc;
@@ -237,6 +248,7 @@ static const struct valid_link_pair_case {
enum nl80211_chan_width cw_b;
s32 sig_a;
s32 sig_b;
+ bool csa_a;
bool valid;
} valid_link_pair_cases[] = {
{
@@ -335,6 +347,17 @@ static const struct valid_link_pair_case {
.cw_b = NL80211_CHAN_WIDTH_160,
.valid = true,
},
+ {
+ .desc = "CSA active",
+ .chan_a = &chan_6ghz,
+ .cw_a = NL80211_CHAN_WIDTH_160,
+ .sig_a = -5,
+ .chan_b = &chan_5ghz,
+ .cw_b = NL80211_CHAN_WIDTH_160,
+ .valid = false,
+ /* same as previous entry with valid=true except for CSA */
+ .csa_a = true,
+ },
};
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)
.link_id = 5,
.signal = params->sig_b,
};
+ struct ieee80211_bss_conf *conf;
bool result;
KUNIT_ASSERT_NOT_NULL(test, vif);
@@ -377,7 +401,20 @@ static void test_valid_link_pair(struct kunit *test)
mvm.last_bt_notif.wifi_loss_low_rssi = params->bt;
mvmvif->mvm = &mvm;
+ conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, conf);
+ conf->chanreq.oper = chandef_a;
+ conf->csa_active = params->csa_a;
+ vif->link_conf[link_a.link_id] = (void __rcu *)conf;
+
+ conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, conf);
+ conf->chanreq.oper = chandef_b;
+ vif->link_conf[link_b.link_id] = (void __rcu *)conf;
+
+ wiphy_lock(&wiphy);
result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b);
+ wiphy_unlock(&wiphy);
KUNIT_EXPECT_EQ(test, result, params->valid);
diff --git a/versions b/versions
index d653aa325b..fef7f0ee9b 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:11981:ccb166ee"
+BACKPORTS_GIT_TRACKED="iwlwifi-stack-public:master:11982:bee758fa"