From: Ben Greear <greearb@xxxxxxxxxxxxxxx> In case there are no IEs found that report channel load, use channel load reported by the radio firmware. Save related information and display it in debugfs to better understand what is happening. Improve debugging in related code. Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx> --- .../net/wireless/intel/iwlwifi/mvm/debugfs.c | 43 +++++++ drivers/net/wireless/intel/iwlwifi/mvm/link.c | 116 +++++++++++------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 23 ++-- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 4 + 4 files changed, 135 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 91ca830a7b60..23797b1329aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 272da41567ef..04a2f6c83b3c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -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 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2ad615293c75..751d2c2bf541 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 9e72db9bab40..7f285ee49097 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -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); } } -- 2.42.0