Commit 30ce0390 authored by Miri Korenblit's avatar Miri Korenblit Committed by Johannes Berg

wifi: iwlwifi: mvm: Don't allow EMLSR when the RSSI is low

If the RSSI of a link is low enough, don't use it for EMLSR.
If EMLSR is already active and the RSSI of one of the links gets low,
exit EMLSR by deactivating that link.
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240416134215.73263c000263.Ieb2b18855a2719b5e18ad2fa8a3e855ca4e23938@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 54fa45dd
...@@ -125,4 +125,13 @@ ...@@ -125,4 +125,13 @@
#define IWL_MVM_AUTO_EML_ENABLE true #define IWL_MVM_AUTO_EML_ENABLE true
#define IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH 7 #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 */ #endif /* __MVM_CONSTANTS_H */
...@@ -537,7 +537,8 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif, ...@@ -537,7 +537,8 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
continue; continue;
data[n_data].link_id = link_id; 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); data[n_data].grade = iwl_mvm_get_link_grade(link_conf);
if (data[n_data].grade > max_grade) { if (data[n_data].grade > max_grade) {
...@@ -550,21 +551,83 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif, ...@@ -550,21 +551,83 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
return n_data; 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 VISIBLE_IF_IWLWIFI_KUNIT
bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif, 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 *a,
const struct iwl_mvm_link_sel_data *b) const struct iwl_mvm_link_sel_data *b)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); /* Per-link considerations */
if (iwl_mvm_esr_disallowed_with_link(vif, a) ||
if (a->band == b->band) iwl_mvm_esr_disallowed_with_link(vif, b))
return false; return false;
/* BT Coex effects eSR mode only if one of the link is on LB */ /* Per-combination considerations */
if (a->band == NL80211_BAND_2GHZ || b->band == NL80211_BAND_2GHZ) return a->chandef->chan->band != b->chandef->chan->band;
return !(mvmvif->esr_disable_reason & IWL_MVM_ESR_BLOCKED_COEX);
return true;
} }
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair); EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair);
......
...@@ -358,12 +358,15 @@ struct iwl_mvm_vif_link_info { ...@@ -358,12 +358,15 @@ struct iwl_mvm_vif_link_info {
* in a loop. * in a loop.
* @IWL_MVM_ESR_BLOCKED_WOWLAN: WOWLAN is preventing the enablement of EMLSR * @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_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 { enum iwl_mvm_esr_state {
IWL_MVM_ESR_BLOCKED_COEX = 0x1, IWL_MVM_ESR_BLOCKED_COEX = 0x1,
IWL_MVM_ESR_BLOCKED_PREVENTION = 0x2, IWL_MVM_ESR_BLOCKED_PREVENTION = 0x2,
IWL_MVM_ESR_BLOCKED_WOWLAN = 0x4, IWL_MVM_ESR_BLOCKED_WOWLAN = 0x4,
IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000, IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000,
IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
}; };
#define IWL_MVM_BLOCK_ESR_REASONS 0xffff #define IWL_MVM_BLOCK_ESR_REASONS 0xffff
...@@ -1998,7 +2001,8 @@ u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id); ...@@ -1998,7 +2001,8 @@ u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id);
struct iwl_mvm_link_sel_data { struct iwl_mvm_link_sel_data {
u8 link_id; u8 link_id;
enum nl80211_band band; const struct cfg80211_chan_def *chandef;
s32 signal;
u16 grade; u16 grade;
}; };
...@@ -2881,5 +2885,8 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -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, void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_esr_state reason, enum iwl_mvm_esr_state reason,
u8 link_to_keep); 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__ */ #endif /* __IWL_MVM_H__ */
...@@ -556,8 +556,8 @@ struct iwl_mvm_stat_data_all_macs { ...@@ -556,8 +556,8 @@ struct iwl_mvm_stat_data_all_macs {
struct iwl_stats_ntfy_per_mac *per_mac; struct iwl_stats_ntfy_per_mac *per_mac;
}; };
static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig, static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,
struct iwl_mvm_vif_link_info *link_info) struct iwl_mvm_vif_link_info *link_info)
{ {
struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm; struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm;
struct ieee80211_bss_conf *bss_conf = struct ieee80211_bss_conf *bss_conf =
...@@ -566,6 +566,7 @@ static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig, ...@@ -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 thold = bss_conf->cqm_rssi_thold;
int hyst = bss_conf->cqm_rssi_hyst; int hyst = bss_conf->cqm_rssi_hyst;
int last_event; int last_event;
s8 exit_esr_thresh;
if (sig == 0) { if (sig == 0) {
IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); 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, ...@@ -621,6 +622,20 @@ static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig,
sig, sig,
GFP_KERNEL); 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, static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
...@@ -655,7 +670,7 @@ 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; mvmvif->deflink.beacon_stats.num_beacons;
/* This is used in pre-MLO API so use deflink */ /* 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, 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, ...@@ -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); sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy);
/* This is used in pre-MLO API so use deflink */ /* 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 static inline void
...@@ -906,7 +921,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, ...@@ -906,7 +921,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm,
mvmvif->link[link_id]->beacon_stats.num_beacons; mvmvif->link[link_id]->beacon_stats.num_beacons;
sig = -le32_to_cpu(link_stats->beacon_filter_average_energy); 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, if (WARN_ONCE(mvmvif->id >= MAC_INDEX_AUX,
"invalid mvmvif id: %d", mvmvif->id)) "invalid mvmvif id: %d", mvmvif->id))
......
...@@ -22,6 +22,10 @@ static struct ieee80211_channel chan_2ghz = { ...@@ -22,6 +22,10 @@ static struct ieee80211_channel chan_2ghz = {
.band = NL80211_BAND_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_phy_ctxt ctx = {};
static struct iwl_mvm_vif_link_info mvm_link = { static struct iwl_mvm_vif_link_info mvm_link = {
...@@ -33,6 +37,8 @@ static struct cfg80211_bss bss = {}; ...@@ -33,6 +37,8 @@ static struct cfg80211_bss bss = {};
static struct ieee80211_bss_conf link_conf = {.bss = &bss}; static struct ieee80211_bss_conf link_conf = {.bss = &bss};
static struct iwl_mvm mvm = {};
static const struct link_grading_case { static const struct link_grading_case {
const char *desc; const char *desc;
const struct cfg80211_chan_def chandef; const struct cfg80211_chan_def chandef;
...@@ -212,35 +218,119 @@ kunit_test_suite(link_grading); ...@@ -212,35 +218,119 @@ kunit_test_suite(link_grading);
static const struct valid_link_pair_case { static const struct valid_link_pair_case {
const char *desc; const char *desc;
u32 esr_disable_reason; u32 esr_disable_reason;
enum nl80211_band band_a; struct ieee80211_channel *chan_a;
enum nl80211_band band_b; 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; bool valid;
} valid_link_pair_cases[] = { } valid_link_pair_cases[] = {
{ {
.desc = "HB + UHB, valid.", .desc = "HB + UHB, valid.",
.band_a = NL80211_BAND_5GHZ, .chan_a = &chan_5ghz,
.band_b = NL80211_BAND_6GHZ, .chan_b = &chan_6ghz,
.valid = true, .valid = true,
}, },
{ {
.desc = "LB + HB, no BT.", .desc = "LB + HB, no BT.",
.band_a = NL80211_BAND_2GHZ, .chan_a = &chan_2ghz,
.band_b = NL80211_BAND_5GHZ, .chan_b = &chan_5ghz,
.valid = true, .valid = true,
}, },
{ {
.desc = "LB + HB, with BT.", .desc = "LB + HB, with BT.",
.esr_disable_reason = 0x1, .esr_disable_reason = 0x1,
.band_a = NL80211_BAND_2GHZ, .chan_a = &chan_2ghz,
.band_b = NL80211_BAND_5GHZ, .chan_b = &chan_5ghz,
.valid = false, .valid = false,
}, },
{ {
.desc = "Same band", .desc = "Same band",
.band_a = NL80211_BAND_2GHZ, .chan_a = &chan_2ghz,
.band_b = NL80211_BAND_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, .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) 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) ...@@ -251,24 +341,44 @@ static void test_valid_link_pair(struct kunit *test)
size_t vif_size = sizeof(struct ieee80211_vif) + size_t vif_size = sizeof(struct ieee80211_vif) +
sizeof(struct iwl_mvm_vif); sizeof(struct iwl_mvm_vif);
struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); 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 = { 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 = { struct iwl_mvm_link_sel_data link_b = {
.band = params->band_b, .chandef = &chandef_b,
.link_id = 5,
.signal = params->sig_b,
}; };
bool result; bool result;
KUNIT_ASSERT_NOT_NULL(test, vif); 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 = mvmvif->esr_disable_reason = params->esr_disable_reason;
params->esr_disable_reason; mvmvif->mvm = &mvm;
result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b); result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b);
KUNIT_EXPECT_EQ(test, result, params->valid); KUNIT_EXPECT_EQ(test, result, params->valid);
kunit_kfree(test, vif); kunit_kfree(test, vif);
kunit_kfree(test, trans);
} }
static struct kunit_case valid_link_pair_test_cases[] = { static struct kunit_case valid_link_pair_test_cases[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment