aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/rs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/rs.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c241
1 files changed, 224 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 9f32f2db95bd..194bd1f939ca 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -39,6 +39,7 @@
39#include "sta.h" 39#include "sta.h"
40#include "iwl-op-mode.h" 40#include "iwl-op-mode.h"
41#include "mvm.h" 41#include "mvm.h"
42#include "debugfs.h"
42 43
43#define RS_NAME "iwl-mvm-rs" 44#define RS_NAME "iwl-mvm-rs"
44 45
@@ -1805,7 +1806,7 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
1805 /* Our chip supports Tx STBC and the peer is an HT/VHT STA which 1806 /* Our chip supports Tx STBC and the peer is an HT/VHT STA which
1806 * supports STBC of at least 1*SS 1807 * supports STBC of at least 1*SS
1807 */ 1808 */
1808 if (!lq_sta->stbc) 1809 if (!lq_sta->stbc_capable)
1809 return false; 1810 return false;
1810 1811
1811 if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) 1812 if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -2626,7 +2627,7 @@ static void rs_ht_init(struct iwl_mvm *mvm,
2626 if (mvm->cfg->ht_params->stbc && 2627 if (mvm->cfg->ht_params->stbc &&
2627 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && 2628 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
2628 (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) 2629 (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
2629 lq_sta->stbc = true; 2630 lq_sta->stbc_capable = true;
2630 2631
2631 lq_sta->is_vht = false; 2632 lq_sta->is_vht = false;
2632} 2633}
@@ -2645,7 +2646,12 @@ static void rs_vht_init(struct iwl_mvm *mvm,
2645 if (mvm->cfg->ht_params->stbc && 2646 if (mvm->cfg->ht_params->stbc &&
2646 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && 2647 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
2647 (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) 2648 (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
2648 lq_sta->stbc = true; 2649 lq_sta->stbc_capable = true;
2650
2651 if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
2652 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
2653 (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
2654 lq_sta->bfer_capable = true;
2649 2655
2650 lq_sta->is_vht = true; 2656 lq_sta->is_vht = true;
2651} 2657}
@@ -2778,11 +2784,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
2778 rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); 2784 rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate);
2779 2785
2780 IWL_DEBUG_RATE(mvm, 2786 IWL_DEBUG_RATE(mvm,
2781 "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d\n", 2787 "LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n",
2782 lq_sta->active_legacy_rate, 2788 lq_sta->active_legacy_rate,
2783 lq_sta->active_siso_rate, 2789 lq_sta->active_siso_rate,
2784 lq_sta->active_mimo2_rate, 2790 lq_sta->active_mimo2_rate,
2785 lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc); 2791 lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable,
2792 lq_sta->bfer_capable);
2786 IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", 2793 IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
2787 lq_sta->max_legacy_rate_idx, 2794 lq_sta->max_legacy_rate_idx,
2788 lq_sta->max_siso_rate_idx, 2795 lq_sta->max_siso_rate_idx,
@@ -2916,23 +2923,15 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
2916 u8 valid_tx_ant = 0; 2923 u8 valid_tx_ant = 0;
2917 struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; 2924 struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
2918 bool toggle_ant = false; 2925 bool toggle_ant = false;
2919 bool stbc_allowed = false;
2920 2926
2921 memcpy(&rate, initial_rate, sizeof(rate)); 2927 memcpy(&rate, initial_rate, sizeof(rate));
2922 2928
2923 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); 2929 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
2924 2930
2925 stbc_allowed = rs_stbc_allow(mvm, sta, lq_sta); 2931 /* TODO: remove old API when min FW API hits 14 */
2926 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) { 2932 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
2927 u32 ss_params = RS_SS_PARAMS_VALID; 2933 rs_stbc_allow(mvm, sta, lq_sta))
2928 2934 rate.stbc = true;
2929 if (stbc_allowed)
2930 ss_params |= RS_SS_STBC_ALLOWED;
2931 lq_cmd->ss_params = cpu_to_le32(ss_params);
2932 } else {
2933 /* TODO: remove old API when min FW API hits 14 */
2934 rate.stbc = stbc_allowed;
2935 }
2936 2935
2937 if (is_siso(&rate)) { 2936 if (is_siso(&rate)) {
2938 num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; 2937 num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES;
@@ -2980,6 +2979,142 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
2980 2979
2981} 2980}
2982 2981
2982struct rs_bfer_active_iter_data {
2983 struct ieee80211_sta *exclude_sta;
2984 struct iwl_mvm_sta *bfer_mvmsta;
2985};
2986
2987static void rs_bfer_active_iter(void *_data,
2988 struct ieee80211_sta *sta)
2989{
2990 struct rs_bfer_active_iter_data *data = _data;
2991 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
2992 struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.lq;
2993 u32 ss_params = le32_to_cpu(lq_cmd->ss_params);
2994
2995 if (sta == data->exclude_sta)
2996 return;
2997
2998 /* The current sta has BFER allowed */
2999 if (ss_params & LQ_SS_BFER_ALLOWED) {
3000 WARN_ON_ONCE(data->bfer_mvmsta != NULL);
3001
3002 data->bfer_mvmsta = mvmsta;
3003 }
3004}
3005
3006static int rs_bfer_priority(struct iwl_mvm_sta *sta)
3007{
3008 int prio = -1;
3009 enum nl80211_iftype viftype = ieee80211_vif_type_p2p(sta->vif);
3010
3011 switch (viftype) {
3012 case NL80211_IFTYPE_AP:
3013 case NL80211_IFTYPE_P2P_GO:
3014 prio = 3;
3015 break;
3016 case NL80211_IFTYPE_P2P_CLIENT:
3017 prio = 2;
3018 break;
3019 case NL80211_IFTYPE_STATION:
3020 prio = 1;
3021 break;
3022 default:
3023 WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id);
3024 prio = -1;
3025 }
3026
3027 return prio;
3028}
3029
3030/* Returns >0 if sta1 has a higher BFER priority compared to sta2 */
3031static int rs_bfer_priority_cmp(struct iwl_mvm_sta *sta1,
3032 struct iwl_mvm_sta *sta2)
3033{
3034 int prio1 = rs_bfer_priority(sta1);
3035 int prio2 = rs_bfer_priority(sta2);
3036
3037 if (prio1 > prio2)
3038 return 1;
3039 if (prio1 < prio2)
3040 return -1;
3041 return 0;
3042}
3043
3044static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
3045 struct ieee80211_sta *sta,
3046 struct iwl_lq_sta *lq_sta,
3047 const struct rs_rate *initial_rate)
3048{
3049 struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
3050 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
3051 struct rs_bfer_active_iter_data data = {
3052 .exclude_sta = sta,
3053 .bfer_mvmsta = NULL,
3054 };
3055 struct iwl_mvm_sta *bfer_mvmsta = NULL;
3056 u32 ss_params = LQ_SS_PARAMS_VALID;
3057
3058 if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
3059 goto out;
3060
3061 /* Check if forcing the decision is configured.
3062 * Note that SISO is forced by not allowing STBC or BFER
3063 */
3064 if (lq_sta->ss_force == RS_SS_FORCE_STBC)
3065 ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE);
3066 else if (lq_sta->ss_force == RS_SS_FORCE_BFER)
3067 ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE);
3068
3069 if (lq_sta->ss_force != RS_SS_FORCE_NONE) {
3070 IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n",
3071 lq_sta->ss_force);
3072 goto out;
3073 }
3074
3075 if (lq_sta->stbc_capable)
3076 ss_params |= LQ_SS_STBC_1SS_ALLOWED;
3077
3078 if (!lq_sta->bfer_capable)
3079 goto out;
3080
3081 ieee80211_iterate_stations_atomic(mvm->hw,
3082 rs_bfer_active_iter,
3083 &data);
3084 bfer_mvmsta = data.bfer_mvmsta;
3085
3086 /* This code is safe as it doesn't run concurrently for different
3087 * stations. This is guaranteed by the fact that calls to
3088 * ieee80211_tx_status wouldn't run concurrently for a single HW.
3089 */
3090 if (!bfer_mvmsta) {
3091 IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n");
3092
3093 ss_params |= LQ_SS_BFER_ALLOWED;
3094 goto out;
3095 }
3096
3097 IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n",
3098 bfer_mvmsta->sta_id);
3099
3100 /* Disallow BFER on another STA if active and we're a higher priority */
3101 if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) {
3102 struct iwl_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.lq;
3103 u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params);
3104
3105 bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED;
3106 bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params);
3107 iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false);
3108
3109 ss_params |= LQ_SS_BFER_ALLOWED;
3110 IWL_DEBUG_RATE(mvm,
3111 "Lower priority BFER sta found (%d). Switch BFER\n",
3112 bfer_mvmsta->sta_id);
3113 }
3114out:
3115 lq_cmd->ss_params = cpu_to_le32(ss_params);
3116}
3117
2983static void rs_fill_lq_cmd(struct iwl_mvm *mvm, 3118static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
2984 struct ieee80211_sta *sta, 3119 struct ieee80211_sta *sta,
2985 struct iwl_lq_sta *lq_sta, 3120 struct iwl_lq_sta *lq_sta,
@@ -3006,6 +3141,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
3006 3141
3007 rs_build_rates_table(mvm, sta, lq_sta, initial_rate); 3142 rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
3008 3143
3144 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS)
3145 rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate);
3146
3009 if (num_of_ant(initial_rate->ant) == 1) 3147 if (num_of_ant(initial_rate->ant) == 1)
3010 lq_cmd->single_stream_ant_msk = initial_rate->ant; 3148 lq_cmd->single_stream_ant_msk = initial_rate->ant;
3011 3149
@@ -3379,9 +3517,73 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = {
3379 .llseek = default_llseek, 3517 .llseek = default_llseek,
3380}; 3518};
3381 3519
3520static ssize_t iwl_dbgfs_ss_force_read(struct file *file,
3521 char __user *user_buf,
3522 size_t count, loff_t *ppos)
3523{
3524 struct iwl_lq_sta *lq_sta = file->private_data;
3525 char buf[12];
3526 int bufsz = sizeof(buf);
3527 int pos = 0;
3528 static const char * const ss_force_name[] = {
3529 [RS_SS_FORCE_NONE] = "none",
3530 [RS_SS_FORCE_STBC] = "stbc",
3531 [RS_SS_FORCE_BFER] = "bfer",
3532 [RS_SS_FORCE_SISO] = "siso",
3533 };
3534
3535 pos += scnprintf(buf+pos, bufsz-pos, "%s\n",
3536 ss_force_name[lq_sta->ss_force]);
3537 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
3538}
3539
3540static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
3541 size_t count, loff_t *ppos)
3542{
3543 struct iwl_mvm *mvm = lq_sta->pers.drv;
3544 int ret = 0;
3545
3546 if (!strncmp("none", buf, 4)) {
3547 lq_sta->ss_force = RS_SS_FORCE_NONE;
3548 } else if (!strncmp("siso", buf, 4)) {
3549 lq_sta->ss_force = RS_SS_FORCE_SISO;
3550 } else if (!strncmp("stbc", buf, 4)) {
3551 if (lq_sta->stbc_capable) {
3552 lq_sta->ss_force = RS_SS_FORCE_STBC;
3553 } else {
3554 IWL_ERR(mvm,
3555 "can't force STBC. peer doesn't support\n");
3556 ret = -EINVAL;
3557 }
3558 } else if (!strncmp("bfer", buf, 4)) {
3559 if (lq_sta->bfer_capable) {
3560 lq_sta->ss_force = RS_SS_FORCE_BFER;
3561 } else {
3562 IWL_ERR(mvm,
3563 "can't force BFER. peer doesn't support\n");
3564 ret = -EINVAL;
3565 }
3566 } else {
3567 IWL_ERR(mvm, "valid values none|siso|stbc|bfer\n");
3568 ret = -EINVAL;
3569 }
3570 return ret ?: count;
3571}
3572
3573#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
3574 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_lq_sta)
3575#define MVM_DEBUGFS_ADD_FILE_RS(name, parent, mode) do { \
3576 if (!debugfs_create_file(#name, mode, parent, lq_sta, \
3577 &iwl_dbgfs_##name##_ops)) \
3578 goto err; \
3579 } while (0)
3580
3581MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32);
3582
3382static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) 3583static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
3383{ 3584{
3384 struct iwl_lq_sta *lq_sta = mvm_sta; 3585 struct iwl_lq_sta *lq_sta = mvm_sta;
3586
3385 debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, 3587 debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
3386 lq_sta, &rs_sta_dbgfs_scale_table_ops); 3588 lq_sta, &rs_sta_dbgfs_scale_table_ops);
3387 debugfs_create_file("rate_stats_table", S_IRUSR, dir, 3589 debugfs_create_file("rate_stats_table", S_IRUSR, dir,
@@ -3392,6 +3594,11 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
3392 &lq_sta->tx_agg_tid_en); 3594 &lq_sta->tx_agg_tid_en);
3393 debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, 3595 debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir,
3394 &lq_sta->pers.dbg_fixed_txp_reduction); 3596 &lq_sta->pers.dbg_fixed_txp_reduction);
3597
3598 MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR);
3599 return;
3600err:
3601 IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n");
3395} 3602}
3396 3603
3397static void rs_remove_debugfs(void *mvm, void *mvm_sta) 3604static void rs_remove_debugfs(void *mvm, void *mvm_sta)