@@ -1062,6 +1062,49 @@ static ssize_t iwl_dbgfs_fw_system_stats_read(struct file *file,
"accu_radio_stats.tx_time %lld\n",
mvm->accu_radio_stats.tx_time);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.esr_disable_reason: 0x%x\n",
+ mvmvif->esr_disable_reason);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.link_selection_res: 0x%x\n",
+ mvmvif->link_selection_res);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.primary_link: %d\n",
+ mvmvif->primary_link);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.link_selection_primary: %d\n",
+ mvmvif->link_selection_primary);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.last_esr_exit: ts: %lu reason: 0x%x\n",
+ mvmvif->last_esr_exit.ts, mvmvif->last_esr_exit.reason);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.esr_active: %d\n",
+ mvmvif->esr_active);
+ pos += scnprintf(pos, endpos - pos,
+ "mvmvif.esr_active: %d\n",
+ mvmvif->esr_active);
+ for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
+ struct iwl_mvm_link_sel_data *d = &mvm->link_sel_data[i];
+
+ if (d->link_id == -1 || !d->chandef)
+ continue;
+
+ pos += scnprintf(pos, endpos - pos,
+ "link-sel-data[%d] link-id: %d freq: %d signal: %d grade: %d chan-load: %d load-by-us: %d punc-penalty: %d\n",
+ i, d->link_id, d->center_freq1, d->signal, d->grade,
+ d->chan_load, d->channel_load_by_us,
+ d->puncturing_penalty);
+ }
+ for (i = 0; i < NUM_PHY_CTX; i++) {
+ if (!mvm->phy_ctxts[i].ref)
+ continue;
+ pos += scnprintf(pos, endpos - pos,
+ "phy-ctxtx[%d] channel-load: %d load-by-us: %d not-by-us: %d\n",
+ i, mvm->phy_ctxts[i].channel_load,
+ mvm->phy_ctxts[i].channel_load_by_us,
+ mvm->phy_ctxts[i].channel_load_not_by_us);
+ }
+
release_send_out:
mutex_unlock(&mvm->mutex);
@@ -485,13 +485,16 @@ static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = {
#define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100)
static unsigned int
-iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf)
+iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf,
+ struct iwl_mvm_link_sel_data *data)
{
enum nl80211_chan_width chan_width =
link_conf->chanreq.oper.width;
int mhz = nl80211_chan_width_to_mhz(chan_width);
unsigned int n_subchannels, n_punctured, puncturing_penalty;
+ data->puncturing_penalty = 0;
+
if (WARN_ONCE(mhz < 20 || mhz > 320,
"Invalid channel width : (%d)\n", mhz))
return SCALE_FACTOR;
@@ -506,21 +509,26 @@ iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf)
n_punctured = hweight16(link_conf->chanreq.oper.punctured);
puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels;
+ data->puncturing_penalty = puncturing_penalty;
return SCALE_FACTOR - puncturing_penalty;
}
static unsigned int
-iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
+iwl_mvm_get_chan_load(struct iwl_mvm *mvm,
+ struct ieee80211_bss_conf *link_conf,
+ struct iwl_mvm_link_sel_data *data)
{
struct ieee80211_vif *vif = link_conf->vif;
struct iwl_mvm_vif_link_info *mvm_link =
iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id];
const struct element *bss_load_elem;
const struct ieee80211_bss_load_elem *bss_load;
- enum nl80211_band band = link_conf->chanreq.oper.chan->band;
const struct cfg80211_bss_ies *ies;
unsigned int chan_load;
u32 chan_load_by_us;
+ const char *load_from = "ies";
+
+ data->channel_load_by_us = 0;
rcu_read_lock();
if (ieee80211_vif_link_active(vif, link_conf->link_id))
@@ -534,33 +542,20 @@ iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
else
bss_load_elem = NULL;
- /* If there isn't BSS Load element, take the defaults */
+ /* If there isn't BSS Load element, get it from our phy-ctx stats */
if (!bss_load_elem ||
bss_load_elem->datalen != sizeof(*bss_load)) {
- rcu_read_unlock();
- switch (band) {
- case NL80211_BAND_2GHZ:
- chan_load = DEFAULT_CHAN_LOAD_LB;
- break;
- case NL80211_BAND_5GHZ:
- chan_load = DEFAULT_CHAN_LOAD_HB;
- break;
- case NL80211_BAND_6GHZ:
- chan_load = DEFAULT_CHAN_LOAD_UHB;
- break;
- default:
- chan_load = 0;
- break;
- }
- /* The defaults are given in percentage */
- return NORMALIZE_PERCENT_TO_255(chan_load);
+ chan_load = NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load);
+ load_from = "phy_ctx";
+ } else {
+ bss_load = (const void *)bss_load_elem->data;
+ /* Channel util is in range 0-255 */
+ chan_load = bss_load->channel_util;
}
-
- bss_load = (const void *)bss_load_elem->data;
- /* Channel util is in range 0-255 */
- chan_load = bss_load->channel_util;
rcu_read_unlock();
+ data->chan_load = chan_load;
+
if (!mvm_link || !mvm_link->active)
return chan_load;
@@ -572,6 +567,12 @@ iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
/* channel load by us is given in percentage */
chan_load_by_us =
NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us);
+ data->channel_load_by_us = chan_load_by_us;
+
+ IWL_DEBUG_INFO(mvm,
+ "Link %d chan-load from %s: %d chan-load-by-us: %d link-active: %d\n",
+ link_conf->link_id, load_from, chan_load, chan_load_by_us,
+ ieee80211_vif_link_active(vif, link_conf->link_id));
/* Use only values that firmware sends that can possibly be valid */
if (chan_load_by_us <= chan_load)
@@ -581,19 +582,24 @@ iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
}
static unsigned int
-iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf)
+iwl_mvm_get_chan_load_factor(struct iwl_mvm *mvm,
+ struct ieee80211_bss_conf *link_conf,
+ struct iwl_mvm_link_sel_data *data)
{
- return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf);
+ return SCALE_FACTOR - iwl_mvm_get_chan_load(mvm, link_conf, data);
}
/* This function calculates the grade of a link. Returns 0 in error case */
VISIBLE_IF_IWLWIFI_KUNIT
-unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf)
+unsigned int iwl_mvm_get_link_grade(struct iwl_mvm *mvm,
+ struct ieee80211_bss_conf *link_conf,
+ struct iwl_mvm_link_sel_data *data)
{
enum nl80211_band band;
int i, rssi_idx;
s32 link_rssi;
unsigned int grade = MAX_GRADE;
+ unsigned int rssi_grade;
if (WARN_ON_ONCE(!link_conf))
return 0;
@@ -629,16 +635,23 @@ unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf)
grade = line->grade;
break;
}
+ rssi_grade = grade;
/* apply the channel load and puncturing factors */
- grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR;
- grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR;
+ grade = grade * iwl_mvm_get_chan_load_factor(mvm, link_conf, data) / SCALE_FACTOR;
+ grade = grade * iwl_mvm_get_puncturing_factor(link_conf, data) / SCALE_FACTOR;
+
+ IWL_DEBUG_INFO(mvm,
+ "Link %d rssi-grade: %d final grade: %d\n",
+ link_conf->link_id, rssi_grade, grade);
+
return grade;
}
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade);
static
-u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
+u8 iwl_mvm_set_link_selection_data(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
struct iwl_mvm_link_sel_data *data,
unsigned long usable_links,
u8 *best_link_idx)
@@ -657,8 +670,9 @@ u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
data[n_data].link_id = link_id;
data[n_data].chandef = &link_conf->chanreq.oper;
+ data[n_data].center_freq1 = link_conf->chanreq.oper.center_freq1;
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(mvm, link_conf, &data[n_data]);
if (data[n_data].grade > max_grade) {
max_grade = data[n_data].grade;
@@ -733,8 +747,12 @@ iwl_mvm_esr_disallowed_with_link(struct iwl_mvm *mvm,
thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef,
false);
- if (link->signal < thresh)
+ if (link->signal < thresh) {
+ IWL_DEBUG_INFO(mvm,
+ "esr-disallowed-low-rssi, Link %d signal: %d thresh: %d freq: %d\n",
+ link->link_id, link->signal, thresh, link->center_freq1);
ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
+ }
if (conf->csa_active)
ret |= IWL_MVM_ESR_EXIT_CSA;
@@ -785,9 +803,10 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair);
* Returns 0 if eSR is not allowed with these 2 links.
*/
static
-unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif,
- const struct iwl_mvm_link_sel_data *a,
- const struct iwl_mvm_link_sel_data *b,
+unsigned int iwl_mvm_get_esr_grade(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_link_sel_data *a,
+ struct iwl_mvm_link_sel_data *b,
u8 *primary_id)
{
struct ieee80211_bss_conf *primary_conf;
@@ -810,7 +829,7 @@ unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif,
if (WARN_ON_ONCE(!primary_conf))
return 0;
- primary_load = iwl_mvm_get_chan_load(primary_conf);
+ primary_load = iwl_mvm_get_chan_load(mvm, primary_conf, a);
return a->grade +
((b->grade * primary_load) / SCALE_FACTOR);
@@ -818,13 +837,20 @@ unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif,
void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
- struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct iwl_mvm_link_sel_data *link_sel_data = mvm->link_sel_data;
struct iwl_mvm_link_sel_data *best_link;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 max_active_links = iwl_mvm_max_active_links(mvm, vif);
u16 usable_links = ieee80211_vif_usable_links(vif);
u8 best, primary_link, best_in_pair, n_data;
u16 max_esr_grade = 0, new_active_links;
+ int z;
+
+ /* Mark links un-used for debugfs to know what to print. */
+ for (z = 0; z < IEEE80211_MLD_MAX_NUM_LINKS; z++) {
+ link_sel_data[z].link_id = -1;
+ link_sel_data[z].chandef = NULL;
+ }
lockdep_assert_wiphy(mvm->hw->wiphy);
@@ -839,13 +865,15 @@ void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
*/
WARN_ON_ONCE(max_active_links > 2);
- n_data = iwl_mvm_set_link_selection_data(vif, data, usable_links,
+ IWL_DEBUG_INFO(mvm, "iwl-mvm-select-links, max-active: %d usable: %d\n",
+ max_active_links, usable_links);
+ n_data = iwl_mvm_set_link_selection_data(mvm, vif, link_sel_data, usable_links,
&best);
if (WARN(!n_data, "Couldn't find a valid grade for any link!\n"))
return;
- best_link = &data[best];
+ best_link = &link_sel_data[best];
primary_link = best_link->link_id;
new_active_links = BIT(best_link->link_id);
@@ -856,8 +884,8 @@ void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
for (u8 a = 0; a < n_data; a++)
for (u8 b = a + 1; b < n_data; b++) {
- u16 esr_grade = iwl_mvm_get_esr_grade(vif, &data[a],
- &data[b],
+ u16 esr_grade = iwl_mvm_get_esr_grade(mvm, vif, &link_sel_data[a],
+ &link_sel_data[b],
&best_in_pair);
if (esr_grade <= max_esr_grade)
@@ -865,8 +893,8 @@ void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
max_esr_grade = esr_grade;
primary_link = best_in_pair;
- new_active_links = BIT(data[a].link_id) |
- BIT(data[b].link_id);
+ new_active_links = BIT(link_sel_data[a].link_id) |
+ BIT(link_sel_data[b].link_id);
}
/* No valid pair was found, go with the best link */
@@ -102,7 +102,9 @@ struct iwl_mvm_phy_ctxt {
/* track for RLC config command */
u32 center_freq1;
bool rlc_disabled;
+ u32 channel_load;
u32 channel_load_by_us;
+ u32 channel_load_not_by_us;
};
struct iwl_mvm_time_event_data {
@@ -992,6 +994,18 @@ struct iwl_mvm_acs_survey {
struct iwl_mvm_acs_survey_channel channels[] __counted_by(n_channels);
};
+struct iwl_mvm_link_sel_data {
+ u8 link_id;
+ const struct cfg80211_chan_def *chandef;
+ /* so we don't have to reference maybe stale chandef in debugfs */
+ u32 center_freq1;
+ s32 signal;
+ u16 grade;
+ u16 chan_load; /* reported by AP BSS Load IE */
+ u16 channel_load_by_us; /* reported by firmware */
+ u16 puncturing_penalty; /* driver calculates */
+};
+
struct iwl_mvm {
/* for logger access */
struct device *dev;
@@ -1174,6 +1188,8 @@ struct iwl_mvm {
struct ieee80211_bss_conf __rcu *link_id_to_link_conf[IWL_FW_MAX_LINK_ID + 1];
+ struct iwl_mvm_link_sel_data link_sel_data[IEEE80211_MLD_MAX_NUM_LINKS];
+
/* -1 for always, 0 for never, >0 for that many times */
s8 fw_restart;
u8 *error_recovery_buf;
@@ -2124,13 +2140,6 @@ void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif);
u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id);
-struct iwl_mvm_link_sel_data {
- u8 link_id;
- const struct cfg80211_chan_def *chandef;
- s32 signal;
- u16 grade;
-};
-
#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf);
bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
@@ -787,8 +787,12 @@ static void iwl_mvm_handle_per_phy_stats(struct iwl_mvm *mvm,
for (i = 0; i < NUM_PHY_CTX; i++) {
if (!mvm->phy_ctxts[i].ref)
continue;
+ mvm->phy_ctxts[i].channel_load =
+ le32_to_cpu(per_phy[i].channel_load);
mvm->phy_ctxts[i].channel_load_by_us =
le32_to_cpu(per_phy[i].channel_load_by_us);
+ mvm->phy_ctxts[i].channel_load_not_by_us =
+ le32_to_cpu(per_phy[i].channel_load_not_by_us);
}
}