From df966c93f5a9c060df525272d9c1eb37795a88f5 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 6 May 2024 10:04:17 +0300 Subject: wifi: iwlwifi: mvm: exit EMLSR if secondary link is not used Exit EMLSR mode if the secondary link is not used enough for Rx/Tx Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://msgid.link/20240506095953.99ad1d71e9b9.Ide825433488ec809773efdc36937e3089d0012df@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 37 ++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 7e567a0b16ae..6ec9a8e21a34 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -15,7 +15,8 @@ HOW(EXIT_LOW_RSSI) \ HOW(EXIT_COEX) \ HOW(EXIT_BANDWIDTH) \ - HOW(EXIT_CSA) + HOW(EXIT_CSA) \ + HOW(EXIT_LINK_USAGE) static const char *const iwl_mvm_esr_states_names[] = { #define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b96568f5640c..1f58c727fa63 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -369,6 +369,7 @@ struct iwl_mvm_vif_link_info { * @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 + * @IWL_MVM_ESR_EXIT_LINK_USAGE: Exit EMLSR due to low tpt on secondary link */ enum iwl_mvm_esr_state { IWL_MVM_ESR_BLOCKED_PREVENTION = 0x1, @@ -381,6 +382,7 @@ enum iwl_mvm_esr_state { IWL_MVM_ESR_EXIT_COEX = 0x40000, IWL_MVM_ESR_EXIT_BANDWIDTH = 0x80000, IWL_MVM_ESR_EXIT_CSA = 0x100000, + IWL_MVM_ESR_EXIT_LINK_USAGE = 0x200000, }; #define IWL_MVM_BLOCK_ESR_REASONS 0xffff diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 36083905457b..4fa8066a89b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -951,12 +951,19 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, } } +#define SEC_LINK_MIN_PERC 10 +#define SEC_LINK_MIN_TX 3000 +#define SEC_LINK_MIN_RX 400 + static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm) { struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); struct iwl_mvm_vif *mvmvif; struct iwl_mvm_sta *mvmsta; unsigned long total_tx = 0, total_rx = 0; + unsigned long sec_link_tx = 0, sec_link_rx = 0; + u8 sec_link_tx_perc, sec_link_rx_perc; + u8 sec_link; lockdep_assert_held(&mvm->mutex); @@ -973,6 +980,13 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm) if (!mvmsta->mpdu_counters) return; + /* Get the FW ID of the secondary link */ + sec_link = iwl_mvm_get_other_link(bss_vif, + iwl_mvm_get_primary_link(bss_vif)); + if (WARN_ON(!mvmvif->link[sec_link])) + return; + sec_link = mvmvif->link[sec_link]->fw_link_id; + /* Sum up RX and TX MPDUs from the different queues/links */ for (int q = 0; q < mvm->trans->num_rx_queues; q++) { spin_lock_bh(&mvmsta->mpdu_counters[q].lock); @@ -982,6 +996,10 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm) total_tx += mvmsta->mpdu_counters[q].per_link[link].tx; total_rx += mvmsta->mpdu_counters[q].per_link[link].rx; } + + sec_link_tx += mvmsta->mpdu_counters[q].per_link[sec_link].tx; + sec_link_rx += mvmsta->mpdu_counters[q].per_link[sec_link].rx; + /* * In EMLSR we have statistics every 5 seconds, so we can reset * the counters upon every statistics notification. @@ -994,9 +1012,26 @@ static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm) /* If we don't have enough MPDUs - exit EMLSR */ if (total_tx < IWL_MVM_ENTER_ESR_TPT_THRESH && - total_rx < IWL_MVM_ENTER_ESR_TPT_THRESH) + total_rx < IWL_MVM_ENTER_ESR_TPT_THRESH) { iwl_mvm_block_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_TPT, iwl_mvm_get_primary_link(bss_vif)); + return; + } + + /* Calculate the percentage of the secondary link TX/RX */ + sec_link_tx_perc = total_tx ? sec_link_tx * 100 / total_tx : 0; + sec_link_rx_perc = total_rx ? sec_link_rx * 100 / total_rx : 0; + + /* + * The TX/RX percentage is checked only if it exceeds the required + * minimum. In addition, RX is checked only if the TX check failed. + */ + if ((total_tx > SEC_LINK_MIN_TX && + sec_link_tx_perc < SEC_LINK_MIN_PERC) || + (total_rx > SEC_LINK_MIN_RX && + sec_link_rx_perc < SEC_LINK_MIN_PERC)) + iwl_mvm_exit_esr(mvm, bss_vif, IWL_MVM_ESR_EXIT_LINK_USAGE, + iwl_mvm_get_primary_link(bss_vif)); } void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, -- cgit v1.2.3