summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/link.c81
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c138
5 files changed, 233 insertions, 29 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index a79395d8c0f1..d80b21ffbc0a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -125,4 +125,13 @@
#define IWL_MVM_AUTO_EML_ENABLE true
#define IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH 7
+#define IWL_MVM_HIGH_RSSI_THRESH_20MHZ -67
+#define IWL_MVM_LOW_RSSI_THRESH_20MHZ -71
+#define IWL_MVM_HIGH_RSSI_THRESH_40MHZ -64
+#define IWL_MVM_LOW_RSSI_THRESH_40MHZ -67
+#define IWL_MVM_HIGH_RSSI_THRESH_80MHZ -61
+#define IWL_MVM_LOW_RSSI_THRESH_80MHZ -74
+#define IWL_MVM_HIGH_RSSI_THRESH_160MHZ -58
+#define IWL_MVM_LOW_RSSI_THRESH_160MHZ -61
+
#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index 1171fc831ca8..ae45aa56d01d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -537,7 +537,8 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
continue;
data[n_data].link_id = link_id;
- data[n_data].band = link_conf->chanreq.oper.chan->band;
+ data[n_data].chandef = &link_conf->chanreq.oper;
+ data[n_data].signal = link_conf->bss->signal / 100;
data[n_data].grade = iwl_mvm_get_link_grade(link_conf);
if (data[n_data].grade > max_grade) {
@@ -550,21 +551,83 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
return n_data;
}
+struct iwl_mvm_bw_to_rssi_threshs {
+ s8 low;
+ s8 high;
+};
+
+#define BW_TO_RSSI_THRESHOLDS(_bw) \
+ [IWL_PHY_CHANNEL_MODE ## _bw] = { \
+ .low = IWL_MVM_LOW_RSSI_THRESH_##_bw##MHZ, \
+ .high = IWL_MVM_HIGH_RSSI_THRESH_##_bw##MHZ \
+ }
+
+s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm,
+ const struct cfg80211_chan_def *chandef,
+ bool low)
+{
+ const struct iwl_mvm_bw_to_rssi_threshs bw_to_rssi_threshs_map[] = {
+ BW_TO_RSSI_THRESHOLDS(20),
+ BW_TO_RSSI_THRESHOLDS(40),
+ BW_TO_RSSI_THRESHOLDS(80),
+ BW_TO_RSSI_THRESHOLDS(160)
+ /* 320 MHz has the same thresholds as 20 MHz */
+ };
+ const struct iwl_mvm_bw_to_rssi_threshs *threshs;
+ u8 chan_width = iwl_mvm_get_channel_width(chandef);
+
+ if (WARN_ON(chandef->chan->band != NL80211_BAND_2GHZ &&
+ chandef->chan->band != NL80211_BAND_5GHZ &&
+ chandef->chan->band != NL80211_BAND_6GHZ))
+ return S8_MAX;
+
+ /* 6 GHz will always use 20 MHz thresholds, regardless of the BW */
+ if (chan_width == IWL_PHY_CHANNEL_MODE320)
+ chan_width = IWL_PHY_CHANNEL_MODE20;
+
+ threshs = &bw_to_rssi_threshs_map[chan_width];
+
+ return low ? threshs->low : threshs->high;
+}
+
+static u32
+iwl_mvm_esr_disallowed_with_link(struct ieee80211_vif *vif,
+ const struct iwl_mvm_link_sel_data *link)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ enum iwl_mvm_esr_state ret = 0;
+ s8 thresh;
+
+ /* BT Coex effects eSR mode only if one of the links is on LB */
+ if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
+ mvmvif->esr_disable_reason & IWL_MVM_ESR_BLOCKED_COEX)
+ ret |= IWL_MVM_ESR_BLOCKED_COEX;
+ thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef,
+ false);
+
+ if (link->signal < thresh)
+ ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
+
+ if (ret)
+ IWL_DEBUG_INFO(mvm,
+ "Link %d is not allowed for esr. Reason: 0x%x\n",
+ link->link_id, ret);
+ return ret;
+}
+
VISIBLE_IF_IWLWIFI_KUNIT
bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
const struct iwl_mvm_link_sel_data *a,
const struct iwl_mvm_link_sel_data *b)
{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- if (a->band == b->band)
+ /* Per-link considerations */
+ if (iwl_mvm_esr_disallowed_with_link(vif, a) ||
+ iwl_mvm_esr_disallowed_with_link(vif, b))
return false;
- /* BT Coex effects eSR mode only if one of the link is on LB */
- if (a->band == NL80211_BAND_2GHZ || b->band == NL80211_BAND_2GHZ)
- return !(mvmvif->esr_disable_reason & IWL_MVM_ESR_BLOCKED_COEX);
-
- return true;
+ /* Per-combination considerations */
+ return a->chandef->chan->band != b->chandef->chan->band;
}
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 2ef346c54d24..421c927ec960 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -358,12 +358,15 @@ struct iwl_mvm_vif_link_info {
* in a loop.
* @IWL_MVM_ESR_BLOCKED_WOWLAN: WOWLAN is preventing the enablement of EMLSR
* @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons
+ * @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR
+ * due to low RSSI.
*/
enum iwl_mvm_esr_state {
IWL_MVM_ESR_BLOCKED_COEX = 0x1,
IWL_MVM_ESR_BLOCKED_PREVENTION = 0x2,
IWL_MVM_ESR_BLOCKED_WOWLAN = 0x4,
IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000,
+ IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
};
#define IWL_MVM_BLOCK_ESR_REASONS 0xffff
@@ -1998,7 +2001,8 @@ u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id);
struct iwl_mvm_link_sel_data {
u8 link_id;
- enum nl80211_band band;
+ const struct cfg80211_chan_def *chandef;
+ s32 signal;
u16 grade;
};
@@ -2881,5 +2885,8 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_esr_state reason,
u8 link_to_keep);
+s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm,
+ const struct cfg80211_chan_def *chandef,
+ bool low);
#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 4f578f3e7e74..68ec6b8203df 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -556,8 +556,8 @@ struct iwl_mvm_stat_data_all_macs {
struct iwl_stats_ntfy_per_mac *per_mac;
};
-static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig,
- struct iwl_mvm_vif_link_info *link_info)
+static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,
+ struct iwl_mvm_vif_link_info *link_info)
{
struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm;
struct ieee80211_bss_conf *bss_conf =
@@ -566,6 +566,7 @@ static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig,
int thold = bss_conf->cqm_rssi_thold;
int hyst = bss_conf->cqm_rssi_hyst;
int last_event;
+ s8 exit_esr_thresh;
if (sig == 0) {
IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n");
@@ -621,6 +622,20 @@ static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig,
sig,
GFP_KERNEL);
}
+
+ /* ESR recalculation */
+ if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
+ return;
+
+ exit_esr_thresh =
+ iwl_mvm_get_esr_rssi_thresh(mvm,
+ &bss_conf->chanreq.oper,
+ true);
+
+ if (sig < exit_esr_thresh)
+ iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_LOW_RSSI,
+ iwl_mvm_get_other_link(vif,
+ bss_conf->link_id));
}
static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
@@ -655,7 +670,7 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
mvmvif->deflink.beacon_stats.num_beacons;
/* This is used in pre-MLO API so use deflink */
- iwl_mvm_update_vif_sig(vif, sig, &mvmvif->deflink);
+ iwl_mvm_update_link_sig(vif, sig, &mvmvif->deflink);
}
static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac,
@@ -690,7 +705,7 @@ static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac,
sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy);
/* This is used in pre-MLO API so use deflink */
- iwl_mvm_update_vif_sig(vif, sig, &mvmvif->deflink);
+ iwl_mvm_update_link_sig(vif, sig, &mvmvif->deflink);
}
static inline void
@@ -906,7 +921,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,
mvmvif->link[link_id]->beacon_stats.num_beacons;
sig = -le32_to_cpu(link_stats->beacon_filter_average_energy);
- iwl_mvm_update_vif_sig(bss_conf->vif, sig, link_info);
+ iwl_mvm_update_link_sig(bss_conf->vif, sig, link_info);
if (WARN_ONCE(mvmvif->id >= MAC_INDEX_AUX,
"invalid mvmvif id: %d", mvmvif->id))
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c
index 17ca85465468..7446e0c168ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c
@@ -22,6 +22,10 @@ static struct ieee80211_channel chan_2ghz = {
.band = NL80211_BAND_2GHZ,
};
+static struct cfg80211_chan_def chandef_a = {};
+
+static struct cfg80211_chan_def chandef_b = {};
+
static struct iwl_mvm_phy_ctxt ctx = {};
static struct iwl_mvm_vif_link_info mvm_link = {
@@ -33,6 +37,8 @@ static struct cfg80211_bss bss = {};
static struct ieee80211_bss_conf link_conf = {.bss = &bss};
+static struct iwl_mvm mvm = {};
+
static const struct link_grading_case {
const char *desc;
const struct cfg80211_chan_def chandef;
@@ -212,35 +218,119 @@ kunit_test_suite(link_grading);
static const struct valid_link_pair_case {
const char *desc;
u32 esr_disable_reason;
- enum nl80211_band band_a;
- enum nl80211_band band_b;
+ struct ieee80211_channel *chan_a;
+ struct ieee80211_channel *chan_b;
+ enum nl80211_chan_width cw_a;
+ enum nl80211_chan_width cw_b;
+ s32 sig_a;
+ s32 sig_b;
bool valid;
} valid_link_pair_cases[] = {
{
.desc = "HB + UHB, valid.",
- .band_a = NL80211_BAND_5GHZ,
- .band_b = NL80211_BAND_6GHZ,
+ .chan_a = &chan_5ghz,
+ .chan_b = &chan_6ghz,
.valid = true,
},
{
.desc = "LB + HB, no BT.",
- .band_a = NL80211_BAND_2GHZ,
- .band_b = NL80211_BAND_5GHZ,
+ .chan_a = &chan_2ghz,
+ .chan_b = &chan_5ghz,
.valid = true,
},
{
.desc = "LB + HB, with BT.",
.esr_disable_reason = 0x1,
- .band_a = NL80211_BAND_2GHZ,
- .band_b = NL80211_BAND_5GHZ,
+ .chan_a = &chan_2ghz,
+ .chan_b = &chan_5ghz,
.valid = false,
},
{
.desc = "Same band",
- .band_a = NL80211_BAND_2GHZ,
- .band_b = NL80211_BAND_2GHZ,
+ .chan_a = &chan_2ghz,
+ .chan_b = &chan_2ghz,
+ .valid = false,
+ },
+ {
+ .desc = "RSSI: LB, 20 MHz, low",
+ .chan_a = &chan_2ghz,
+ .cw_a = NL80211_CHAN_WIDTH_20,
+ .sig_a = -68,
+ .chan_b = &chan_5ghz,
+ .valid = false,
+ },
+ {
+ .desc = "RSSI: LB, 20 MHz, high",
+ .chan_a = &chan_2ghz,
+ .cw_a = NL80211_CHAN_WIDTH_20,
+ .sig_a = -66,
+ .chan_b = &chan_5ghz,
+ .valid = true,
+ },
+ {
+ .desc = "RSSI: LB, 40 MHz, low",
+ .chan_a = &chan_2ghz,
+ .cw_a = NL80211_CHAN_WIDTH_40,
+ .sig_a = -65,
+ .chan_b = &chan_5ghz,
+ .valid = false,
+ },
+ {
+ .desc = "RSSI: LB, 40 MHz, high",
+ .chan_a = &chan_2ghz,
+ .cw_a = NL80211_CHAN_WIDTH_40,
+ .sig_a = -63,
+ .chan_b = &chan_5ghz,
+ .valid = true,
+ },
+ {
+ .desc = "RSSI: HB, 80 MHz, low",
+ .chan_a = &chan_5ghz,
+ .cw_a = NL80211_CHAN_WIDTH_80,
+ .sig_a = -62,
+ .chan_b = &chan_2ghz,
.valid = false,
},
+ {
+ .desc = "RSSI: HB, 80 MHz, high",
+ .chan_a = &chan_5ghz,
+ .cw_a = NL80211_CHAN_WIDTH_80,
+ .sig_a = -60,
+ .chan_b = &chan_2ghz,
+ .valid = true,
+ },
+ {
+ .desc = "RSSI: HB, 160 MHz, low",
+ .chan_a = &chan_5ghz,
+ .cw_a = NL80211_CHAN_WIDTH_160,
+ .sig_a = -59,
+ .chan_b = &chan_2ghz,
+ .valid = false,
+ },
+ {
+ .desc = "RSSI: HB, 160 MHz, high",
+ .chan_a = &chan_5ghz,
+ .cw_a = NL80211_CHAN_WIDTH_160,
+ .sig_a = -5,
+ .chan_b = &chan_2ghz,
+ .valid = true,
+ },
+ {
+ .desc = "RSSI: UHB, 320 MHz, low",
+ .chan_a = &chan_6ghz,
+ .cw_a = NL80211_CHAN_WIDTH_320,
+ .sig_a = -68,
+ .chan_b = &chan_6ghz,
+ .valid = false,
+ },
+ {
+ .desc = "RSSI: UHB, 320 MHz, high",
+ .chan_a = &chan_6ghz,
+ .cw_a = NL80211_CHAN_WIDTH_320,
+ .sig_a = -66,
+ .chan_b = &chan_5ghz,
+ .valid = true,
+ },
};
KUNIT_ARRAY_PARAM_DESC(valid_link_pair, valid_link_pair_cases, desc)
@@ -251,24 +341,44 @@ static void test_valid_link_pair(struct kunit *test)
size_t vif_size = sizeof(struct ieee80211_vif) +
sizeof(struct iwl_mvm_vif);
struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL);
+ struct iwl_trans *trans = kunit_kzalloc(test, sizeof(struct iwl_trans),
+ GFP_KERNEL);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_link_sel_data link_a = {
- .band = params->band_a,
+ .chandef = &chandef_a,
+ .link_id = 1,
+ .signal = params->sig_a,
};
struct iwl_mvm_link_sel_data link_b = {
- .band = params->band_b,
+ .chandef = &chandef_b,
+ .link_id = 5,
+ .signal = params->sig_b,
};
bool result;
KUNIT_ASSERT_NOT_NULL(test, vif);
+ KUNIT_ASSERT_NOT_NULL(test, trans);
+
+ chandef_a.chan = params->chan_a;
+ chandef_b.chan = params->chan_b;
+
+ chandef_a.width = params->cw_a ?: NL80211_CHAN_WIDTH_20;
+ chandef_b.width = params->cw_b ?: NL80211_CHAN_WIDTH_20;
+
+#ifdef CONFIG_IWLWIFI_SUPPORT_DEBUG_OVERRIDES
+ trans->dbg_cfg = default_dbg_config;
+#endif
+ mvm.trans = trans;
- iwl_mvm_vif_from_mac80211(vif)->esr_disable_reason =
- params->esr_disable_reason;
+ mvmvif->esr_disable_reason = params->esr_disable_reason;
+ mvmvif->mvm = &mvm;
result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b);
KUNIT_EXPECT_EQ(test, result, params->valid);
kunit_kfree(test, vif);
+ kunit_kfree(test, trans);
}
static struct kunit_case valid_link_pair_test_cases[] = {