Commit d8bafeaf authored by Eyal Shapira's avatar Eyal Shapira Committed by Emmanuel Grumbach

iwlwifi: mvm: rs: add Tx STBC support

STBC is enabled on HT/VHT SISO rates in case we don't care
about power consumption and it won't hurt BT.
This is done only in case the peer and our chip support STBC
of course.
While at it fixed a bug which was causing bw and ldpc
flags to be set incorrectly in the rate scale table in case
we are switching to a legacy Tx column. This had no real impact.
Signed-off-by: default avatarEyal Shapira <eyalx.shapira@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 1e2ebe0e
...@@ -505,10 +505,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) ...@@ -505,10 +505,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
const char *prefix) const char *prefix)
{ {
IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n", IWL_DEBUG_RATE(mvm,
"%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n",
prefix, rs_pretty_lq_type(rate->type), prefix, rs_pretty_lq_type(rate->type),
rate->index, rs_pretty_ant(rate->ant), rate->index, rs_pretty_ant(rate->ant),
rate->bw, rate->sgi, rate->ldpc); rate->bw, rate->sgi, rate->ldpc, rate->stbc);
} }
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
...@@ -741,6 +742,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, ...@@ -741,6 +742,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
} }
if (is_siso(rate) && rate->stbc) {
/* To enable STBC we need to set both a flag and ANT_AB */
ucode_rate |= RATE_MCS_ANT_AB_MSK;
ucode_rate |= RATE_MCS_VHT_STBC_MSK;
}
ucode_rate |= rate->bw; ucode_rate |= rate->bw;
if (rate->sgi) if (rate->sgi)
ucode_rate |= RATE_MCS_SGI_MSK; ucode_rate |= RATE_MCS_SGI_MSK;
...@@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, ...@@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
rate->sgi = true; rate->sgi = true;
if (ucode_rate & RATE_MCS_LDPC_MSK) if (ucode_rate & RATE_MCS_LDPC_MSK)
rate->ldpc = true; rate->ldpc = true;
if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
rate->stbc = true;
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
...@@ -794,7 +803,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, ...@@ -794,7 +803,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
if (nss == 1) { if (nss == 1) {
rate->type = LQ_HT_SISO; rate->type = LQ_HT_SISO;
WARN_ON_ONCE(num_of_ant != 1); WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
} else if (nss == 2) { } else if (nss == 2) {
rate->type = LQ_HT_MIMO2; rate->type = LQ_HT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2); WARN_ON_ONCE(num_of_ant != 2);
...@@ -992,7 +1001,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, ...@@ -992,7 +1001,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
static inline bool rs_rate_match(struct rs_rate *a, static inline bool rs_rate_match(struct rs_rate *a,
struct rs_rate *b) struct rs_rate *b)
{ {
return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi); bool ant_match;
if (a->stbc)
ant_match = (b->ant == ANT_A || b->ant == ANT_B);
else
ant_match = (a->ant == b->ant);
return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi)
&& ant_match;
} }
static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
...@@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, ...@@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
else else
rate->type = LQ_LEGACY_G; rate->type = LQ_LEGACY_G;
rate->bw = RATE_MCS_CHAN_WIDTH_20;
rate->ldpc = false;
rate_mask = lq_sta->active_legacy_rate; rate_mask = lq_sta->active_legacy_rate;
} else if (column->mode == RS_SISO) { } else if (column->mode == RS_SISO) {
rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
...@@ -1634,8 +1653,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, ...@@ -1634,8 +1653,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
WARN_ON_ONCE("Bad column mode"); WARN_ON_ONCE("Bad column mode");
} }
rate->bw = rs_bw_from_sta_bw(sta); if (column->mode != RS_LEGACY) {
rate->ldpc = lq_sta->ldpc; rate->bw = rs_bw_from_sta_bw(sta);
rate->ldpc = lq_sta->ldpc;
}
search_tbl->column = col_id; search_tbl->column = col_id;
rs_set_expected_tpt_table(lq_sta, search_tbl); rs_set_expected_tpt_table(lq_sta, search_tbl);
...@@ -1754,6 +1776,29 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, ...@@ -1754,6 +1776,29 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
return action; return action;
} }
static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_vif *vif = mvmsta->vif;
bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
!vif->bss_conf.ps);
/* Our chip supports Tx STBC and the peer is an HT/VHT STA which
* supports STBC of at least 1*SS
*/
if (!lq_sta->stbc)
return false;
if (!mvm->ps_disabled && !sta_ps_disabled)
return false;
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
return false;
return true;
}
static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
int *weaker, int *stronger) int *weaker, int *stronger)
{ {
...@@ -2675,6 +2720,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -2675,6 +2720,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (mvm->cfg->ht_params->ldpc && if (mvm->cfg->ht_params->ldpc &&
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
lq_sta->ldpc = true; lq_sta->ldpc = true;
if (mvm->cfg->ht_params->stbc &&
(num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
(ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
lq_sta->stbc = true;
} else { } else {
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
lq_sta->is_vht = true; lq_sta->is_vht = true;
...@@ -2682,6 +2732,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -2682,6 +2732,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (mvm->cfg->ht_params->ldpc && if (mvm->cfg->ht_params->ldpc &&
(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
lq_sta->ldpc = true; lq_sta->ldpc = true;
if (mvm->cfg->ht_params->stbc &&
(num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
(vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
lq_sta->stbc = true;
} }
if (IWL_MVM_RS_DISABLE_MIMO) if (IWL_MVM_RS_DISABLE_MIMO)
...@@ -2695,11 +2750,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -2695,11 +2750,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
BITS_PER_LONG); BITS_PER_LONG);
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n", "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
lq_sta->active_legacy_rate, lq_sta->active_legacy_rate,
lq_sta->active_siso_rate, lq_sta->active_siso_rate,
lq_sta->active_mimo2_rate, lq_sta->active_mimo2_rate,
lq_sta->is_vht, lq_sta->ldpc); lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx, lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx, lq_sta->max_siso_rate_idx,
...@@ -2823,6 +2878,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, ...@@ -2823,6 +2878,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
* rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
*/ */
static void rs_build_rates_table(struct iwl_mvm *mvm, static void rs_build_rates_table(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
const struct rs_rate *initial_rate) const struct rs_rate *initial_rate)
{ {
...@@ -2835,6 +2891,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, ...@@ -2835,6 +2891,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
memcpy(&rate, initial_rate, sizeof(rate)); memcpy(&rate, initial_rate, sizeof(rate));
valid_tx_ant = mvm->fw->valid_tx_ant; valid_tx_ant = mvm->fw->valid_tx_ant;
rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
if (is_siso(&rate)) { if (is_siso(&rate)) {
num_rates = RS_INITIAL_SISO_NUM_RATES; num_rates = RS_INITIAL_SISO_NUM_RATES;
...@@ -2906,7 +2963,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, ...@@ -2906,7 +2963,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(!sta || !initial_rate)) if (WARN_ON_ONCE(!sta || !initial_rate))
return; return;
rs_build_rates_table(mvm, lq_sta, initial_rate); rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
if (num_of_ant(initial_rate->ant) == 1) if (num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant; lq_cmd->single_stream_ant_msk = initial_rate->ant;
......
...@@ -208,6 +208,7 @@ struct rs_rate { ...@@ -208,6 +208,7 @@ struct rs_rate {
u32 bw; u32 bw;
bool sgi; bool sgi;
bool ldpc; bool ldpc;
bool stbc;
}; };
...@@ -331,6 +332,7 @@ struct iwl_lq_sta { ...@@ -331,6 +332,7 @@ struct iwl_lq_sta {
u64 last_tx; u64 last_tx;
bool is_vht; bool is_vht;
bool ldpc; /* LDPC Rx is supported by the STA */ bool ldpc; /* LDPC Rx is supported by the STA */
bool stbc; /* Tx STBC is supported by chip and Rx by STA */
enum ieee80211_band band; enum ieee80211_band band;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
......
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