iwlwifi: mvm: support VHT in rs
Enable rs algorithm to use VHT rates and use 80Mhz. This enables reaching VHT rates which wasn't possible. Signed-off-by: Eyal Shapira <eyal@wizery.com> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
4515f30fb6
commit
d310e4059f
|
@ -68,6 +68,7 @@
|
|||
/*
|
||||
* These serve as indexes into
|
||||
* struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT];
|
||||
* TODO: avoid overlap between legacy and HT rates
|
||||
*/
|
||||
enum {
|
||||
IWL_RATE_1M_INDEX = 0,
|
||||
|
@ -121,6 +122,7 @@ enum {
|
|||
IWL_RATE_2M_PLCP = 20,
|
||||
IWL_RATE_5M_PLCP = 55,
|
||||
IWL_RATE_11M_PLCP = 110,
|
||||
IWL_RATE_INVM_PLCP = -1,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -177,6 +179,8 @@ enum {
|
|||
* which is the duplicate 20 MHz MCS (bit 5 set, all others zero.)
|
||||
*/
|
||||
#define RATE_HT_MCS_RATE_CODE_MSK 0x7
|
||||
#define RATE_HT_MCS_NSS_POS 3
|
||||
#define RATE_HT_MCS_NSS_MSK (3 << RATE_HT_MCS_NSS_POS)
|
||||
|
||||
/* Bit 10: (1) Use Green Field preamble */
|
||||
#define RATE_HT_MCS_GF_POS 10
|
||||
|
|
|
@ -586,6 +586,9 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm);
|
|||
/* Utils */
|
||||
int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
|
||||
enum ieee80211_band band);
|
||||
void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_tx_rate *r);
|
||||
u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
|
||||
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_dump_sram(struct iwl_mvm *mvm);
|
||||
|
|
|
@ -82,13 +82,24 @@ static const u8 ant_toggle_lookup[] = {
|
|||
[ANT_ABC] = ANT_ABC,
|
||||
};
|
||||
|
||||
#define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \
|
||||
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
|
||||
IWL_RATE_SISO_##s##M_PLCP, \
|
||||
IWL_RATE_MIMO2_##s##M_PLCP,\
|
||||
IWL_RATE_##rp##M_INDEX, \
|
||||
#define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \
|
||||
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
|
||||
IWL_RATE_HT_SISO_MCS_##s##_PLCP, \
|
||||
IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \
|
||||
IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \
|
||||
IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP,\
|
||||
IWL_RATE_##rp##M_INDEX, \
|
||||
IWL_RATE_##rn##M_INDEX }
|
||||
|
||||
#define IWL_DECLARE_MCS_RATE(s) \
|
||||
[IWL_RATE_MCS_##s##_INDEX] = { IWL_RATE_INVM_PLCP, \
|
||||
IWL_RATE_HT_SISO_MCS_##s##_PLCP, \
|
||||
IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \
|
||||
IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \
|
||||
IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP, \
|
||||
IWL_RATE_INVM_INDEX, \
|
||||
IWL_RATE_INVM_INDEX }
|
||||
|
||||
/*
|
||||
* Parameter order:
|
||||
* rate, ht rate, prev rate, next rate
|
||||
|
@ -102,16 +113,17 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
|
|||
IWL_DECLARE_RATE_INFO(2, INV, 1, 5), /* 2mbps */
|
||||
IWL_DECLARE_RATE_INFO(5, INV, 2, 11), /*5.5mbps */
|
||||
IWL_DECLARE_RATE_INFO(11, INV, 9, 12), /* 11mbps */
|
||||
IWL_DECLARE_RATE_INFO(6, 6, 5, 11), /* 6mbps */
|
||||
IWL_DECLARE_RATE_INFO(9, 6, 6, 11), /* 9mbps */
|
||||
IWL_DECLARE_RATE_INFO(12, 12, 11, 18), /* 12mbps */
|
||||
IWL_DECLARE_RATE_INFO(18, 18, 12, 24), /* 18mbps */
|
||||
IWL_DECLARE_RATE_INFO(24, 24, 18, 36), /* 24mbps */
|
||||
IWL_DECLARE_RATE_INFO(36, 36, 24, 48), /* 36mbps */
|
||||
IWL_DECLARE_RATE_INFO(48, 48, 36, 54), /* 48mbps */
|
||||
IWL_DECLARE_RATE_INFO(54, 54, 48, INV), /* 54mbps */
|
||||
IWL_DECLARE_RATE_INFO(60, 60, 48, INV), /* 60mbps */
|
||||
/* FIXME:RS: ^^ should be INV (legacy) */
|
||||
IWL_DECLARE_RATE_INFO(6, 0, 5, 11), /* 6mbps ; MCS 0 */
|
||||
IWL_DECLARE_RATE_INFO(9, INV, 6, 11), /* 9mbps */
|
||||
IWL_DECLARE_RATE_INFO(12, 1, 11, 18), /* 12mbps ; MCS 1 */
|
||||
IWL_DECLARE_RATE_INFO(18, 2, 12, 24), /* 18mbps ; MCS 2 */
|
||||
IWL_DECLARE_RATE_INFO(24, 3, 18, 36), /* 24mbps ; MCS 3 */
|
||||
IWL_DECLARE_RATE_INFO(36, 4, 24, 48), /* 36mbps ; MCS 4 */
|
||||
IWL_DECLARE_RATE_INFO(48, 5, 36, 54), /* 48mbps ; MCS 5 */
|
||||
IWL_DECLARE_RATE_INFO(54, 6, 48, INV), /* 54mbps ; MCS 6 */
|
||||
IWL_DECLARE_MCS_RATE(7), /* MCS 7 */
|
||||
IWL_DECLARE_MCS_RATE(8), /* MCS 8 */
|
||||
IWL_DECLARE_MCS_RATE(9), /* MCS 9 */
|
||||
};
|
||||
|
||||
static inline u8 rs_extract_rate(u32 rate_n_flags)
|
||||
|
@ -124,26 +136,30 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
|
|||
{
|
||||
int idx = 0;
|
||||
|
||||
/* HT rate format */
|
||||
if (rate_n_flags & RATE_MCS_HT_MSK) {
|
||||
idx = rs_extract_rate(rate_n_flags);
|
||||
idx = rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK;
|
||||
idx += IWL_RATE_MCS_0_INDEX;
|
||||
|
||||
WARN_ON_ONCE(idx >= IWL_RATE_MIMO3_6M_PLCP);
|
||||
if (idx >= IWL_RATE_MIMO2_6M_PLCP)
|
||||
idx = idx - IWL_RATE_MIMO2_6M_PLCP;
|
||||
|
||||
idx += IWL_FIRST_OFDM_RATE;
|
||||
/* skip 9M not supported in ht*/
|
||||
/* skip 9M not supported in HT*/
|
||||
if (idx >= IWL_RATE_9M_INDEX)
|
||||
idx += 1;
|
||||
if ((idx >= IWL_FIRST_HT_RATE) && (idx <= IWL_LAST_HT_RATE))
|
||||
return idx;
|
||||
} else if (rate_n_flags & RATE_MCS_VHT_MSK) {
|
||||
idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
|
||||
idx += IWL_RATE_MCS_0_INDEX;
|
||||
|
||||
/* legacy rate format, search for match in table */
|
||||
/* skip 9M not supported in VHT*/
|
||||
if (idx >= IWL_RATE_9M_INDEX)
|
||||
idx++;
|
||||
if ((idx >= IWL_FIRST_VHT_RATE) && (idx <= IWL_LAST_VHT_RATE))
|
||||
return idx;
|
||||
} else {
|
||||
/* legacy rate format, search for match in table */
|
||||
|
||||
u8 legacy_rate = rs_extract_rate(rate_n_flags);
|
||||
for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
|
||||
if (iwl_rates[idx].plcp ==
|
||||
rs_extract_rate(rate_n_flags))
|
||||
if (iwl_rates[idx].plcp == legacy_rate)
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
@ -200,6 +216,13 @@ static s32 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = {
|
|||
{0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284},
|
||||
};
|
||||
|
||||
static s32 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = {
|
||||
{0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308},
|
||||
{0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312},
|
||||
{0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466},
|
||||
{0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691},
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
|
||||
{0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0},
|
||||
{0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0},
|
||||
|
@ -214,6 +237,13 @@ static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
|
|||
{0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221},
|
||||
};
|
||||
|
||||
static s32 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = {
|
||||
{0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319},
|
||||
{0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320},
|
||||
{0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219},
|
||||
{0, 0, 0, 0, 474, 0, 920, 1338, 1732, 2464, 3116, 3418, 3705, 4225, 4545},
|
||||
};
|
||||
|
||||
/* mbps, mcs */
|
||||
static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
|
||||
{ "1", "BPSK DSSS"},
|
||||
|
@ -424,42 +454,56 @@ static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm,
|
|||
{
|
||||
u32 rate_n_flags = 0;
|
||||
|
||||
rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
|
||||
RATE_MCS_ANT_ABC_MSK);
|
||||
|
||||
if (is_legacy(tbl->lq_type)) {
|
||||
rate_n_flags = iwl_rates[index].plcp;
|
||||
rate_n_flags |= iwl_rates[index].plcp;
|
||||
if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
|
||||
rate_n_flags |= RATE_MCS_CCK_MSK;
|
||||
} else if (is_Ht(tbl->lq_type)) {
|
||||
if (index > IWL_LAST_HT_RATE) {
|
||||
return rate_n_flags;
|
||||
}
|
||||
|
||||
if (is_ht(tbl->lq_type)) {
|
||||
if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) {
|
||||
IWL_ERR(mvm, "Invalid HT rate index %d\n", index);
|
||||
index = IWL_LAST_HT_RATE;
|
||||
}
|
||||
rate_n_flags = RATE_MCS_HT_MSK;
|
||||
rate_n_flags |= RATE_MCS_HT_MSK;
|
||||
|
||||
if (is_siso(tbl->lq_type))
|
||||
rate_n_flags |= iwl_rates[index].plcp_siso;
|
||||
else if (is_mimo2(tbl->lq_type))
|
||||
rate_n_flags |= iwl_rates[index].plcp_mimo2;
|
||||
if (is_ht_siso(tbl->lq_type))
|
||||
rate_n_flags |= iwl_rates[index].plcp_ht_siso;
|
||||
else if (is_ht_mimo2(tbl->lq_type))
|
||||
rate_n_flags |= iwl_rates[index].plcp_ht_mimo2;
|
||||
else
|
||||
WARN_ON_ONCE(1);
|
||||
} else if (is_vht(tbl->lq_type)) {
|
||||
if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) {
|
||||
IWL_ERR(mvm, "Invalid VHT rate index %d\n", index);
|
||||
index = IWL_LAST_VHT_RATE;
|
||||
}
|
||||
rate_n_flags |= RATE_MCS_VHT_MSK;
|
||||
if (is_vht_siso(tbl->lq_type))
|
||||
rate_n_flags |= iwl_rates[index].plcp_vht_siso;
|
||||
else if (is_vht_mimo2(tbl->lq_type))
|
||||
rate_n_flags |= iwl_rates[index].plcp_vht_mimo2;
|
||||
else
|
||||
WARN_ON_ONCE(1);
|
||||
|
||||
} else {
|
||||
IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type);
|
||||
}
|
||||
|
||||
rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
|
||||
RATE_MCS_ANT_ABC_MSK);
|
||||
rate_n_flags |= tbl->bw;
|
||||
if (tbl->is_SGI)
|
||||
rate_n_flags |= RATE_MCS_SGI_MSK;
|
||||
|
||||
if (is_Ht(tbl->lq_type)) {
|
||||
if (tbl->is_ht40)
|
||||
rate_n_flags |= RATE_MCS_CHAN_WIDTH_40;
|
||||
if (tbl->is_SGI)
|
||||
rate_n_flags |= RATE_MCS_SGI_MSK;
|
||||
|
||||
if (use_green) {
|
||||
rate_n_flags |= RATE_HT_MCS_GF_MSK;
|
||||
if (is_siso(tbl->lq_type) && tbl->is_SGI) {
|
||||
rate_n_flags &= ~RATE_MCS_SGI_MSK;
|
||||
IWL_ERR(mvm, "GF was set with SGI:SISO\n");
|
||||
}
|
||||
/* TODO: remove GF completely ? */
|
||||
if (use_green) {
|
||||
rate_n_flags |= RATE_HT_MCS_GF_MSK;
|
||||
if (is_ht_siso(tbl->lq_type) && tbl->is_SGI) {
|
||||
rate_n_flags &= ~RATE_MCS_SGI_MSK;
|
||||
IWL_ERR(mvm, "GF was set with SGI:SISO\n");
|
||||
}
|
||||
}
|
||||
return rate_n_flags;
|
||||
|
@ -476,7 +520,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
|
|||
{
|
||||
u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
|
||||
u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
|
||||
u8 mcs;
|
||||
u8 nss;
|
||||
|
||||
memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win));
|
||||
*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
|
||||
|
@ -486,41 +530,62 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
|
|||
return -EINVAL;
|
||||
}
|
||||
tbl->is_SGI = 0; /* default legacy setup */
|
||||
tbl->is_ht40 = 0;
|
||||
tbl->bw = 0;
|
||||
tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
|
||||
tbl->lq_type = LQ_NONE;
|
||||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
|
||||
/* legacy rate format */
|
||||
if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
|
||||
/* Legacy */
|
||||
if (!(rate_n_flags & RATE_MCS_HT_MSK) &&
|
||||
!(rate_n_flags & RATE_MCS_VHT_MSK)) {
|
||||
if (num_of_ant == 1) {
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
tbl->lq_type = LQ_A;
|
||||
tbl->lq_type = LQ_LEGACY_A;
|
||||
else
|
||||
tbl->lq_type = LQ_G;
|
||||
tbl->lq_type = LQ_LEGACY_G;
|
||||
}
|
||||
/* HT rate format */
|
||||
} else {
|
||||
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
tbl->is_SGI = 1;
|
||||
|
||||
if (rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */
|
||||
tbl->is_ht40 = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mcs = rs_extract_rate(rate_n_flags);
|
||||
/* HT or VHT */
|
||||
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
tbl->is_SGI = 1;
|
||||
|
||||
/* SISO */
|
||||
if (mcs <= IWL_RATE_SISO_60M_PLCP) {
|
||||
if (num_of_ant == 1)
|
||||
tbl->lq_type = LQ_SISO; /*else NONE*/
|
||||
/* MIMO2 */
|
||||
} else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
|
||||
if (num_of_ant == 2)
|
||||
tbl->lq_type = LQ_MIMO2;
|
||||
tbl->bw = rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK;
|
||||
|
||||
if (rate_n_flags & RATE_MCS_HT_MSK) {
|
||||
nss = ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >>
|
||||
RATE_HT_MCS_NSS_POS) + 1;
|
||||
|
||||
if (nss == 1) {
|
||||
tbl->lq_type = LQ_HT_SISO;
|
||||
WARN_ON_ONCE(num_of_ant != 1);
|
||||
} else if (nss == 2) {
|
||||
tbl->lq_type = LQ_HT_MIMO2;
|
||||
WARN_ON_ONCE(num_of_ant != 2);
|
||||
} else {
|
||||
WARN_ON_ONCE(num_of_ant == 3);
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
} else if (rate_n_flags & RATE_MCS_VHT_MSK) {
|
||||
nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
|
||||
RATE_VHT_MCS_NSS_POS) + 1;
|
||||
|
||||
if (nss == 1) {
|
||||
tbl->lq_type = LQ_VHT_SISO;
|
||||
WARN_ON_ONCE(num_of_ant != 1);
|
||||
} else if (nss == 2) {
|
||||
tbl->lq_type = LQ_VHT_MIMO2;
|
||||
WARN_ON_ONCE(num_of_ant != 2);
|
||||
} else {
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_160);
|
||||
WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_80 &&
|
||||
!is_vht(tbl->lq_type));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -579,16 +644,15 @@ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
|
|||
struct ieee80211_hdr *hdr,
|
||||
enum iwl_table_type rate_type)
|
||||
{
|
||||
if (is_legacy(rate_type)) {
|
||||
if (is_legacy(rate_type))
|
||||
return lq_sta->active_legacy_rate;
|
||||
} else {
|
||||
if (is_siso(rate_type))
|
||||
return lq_sta->active_siso_rate;
|
||||
else {
|
||||
WARN_ON_ONCE(!is_mimo2(rate_type));
|
||||
return lq_sta->active_mimo2_rate;
|
||||
}
|
||||
}
|
||||
else if (is_siso(rate_type))
|
||||
return lq_sta->active_siso_rate;
|
||||
else if (is_mimo2(rate_type))
|
||||
return lq_sta->active_mimo2_rate;
|
||||
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
|
||||
|
@ -665,15 +729,15 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
|
|||
switch_to_legacy = 1;
|
||||
scale_index = rs_ht_to_legacy[scale_index];
|
||||
if (lq_sta->band == IEEE80211_BAND_5GHZ)
|
||||
tbl->lq_type = LQ_A;
|
||||
tbl->lq_type = LQ_LEGACY_A;
|
||||
else
|
||||
tbl->lq_type = LQ_G;
|
||||
tbl->lq_type = LQ_LEGACY_G;
|
||||
|
||||
if (num_of_ant(tbl->ant_type) > 1)
|
||||
tbl->ant_type =
|
||||
first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
|
||||
|
||||
tbl->is_ht40 = 0;
|
||||
tbl->bw = 0;
|
||||
tbl->is_SGI = 0;
|
||||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
}
|
||||
|
@ -717,6 +781,18 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
|
|||
(a->is_SGI == b->is_SGI);
|
||||
}
|
||||
|
||||
static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
|
||||
{
|
||||
if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
||||
return RATE_MCS_CHAN_WIDTH_40;
|
||||
else if (flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
|
||||
return RATE_MCS_CHAN_WIDTH_80;
|
||||
else if (flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
|
||||
return RATE_MCS_CHAN_WIDTH_160;
|
||||
|
||||
return RATE_MCS_CHAN_WIDTH_20;
|
||||
}
|
||||
|
||||
/*
|
||||
* mac80211 sends us Tx status
|
||||
*/
|
||||
|
@ -786,16 +862,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
|
|||
*/
|
||||
if (info->band == IEEE80211_BAND_2GHZ)
|
||||
mac_index += IWL_FIRST_OFDM_RATE;
|
||||
} else if (mac_flags & IEEE80211_TX_RC_VHT_MCS) {
|
||||
mac_index &= RATE_VHT_MCS_RATE_CODE_MSK;
|
||||
if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
|
||||
mac_index++;
|
||||
}
|
||||
|
||||
/* Here we actually compare this rate to the latest LQ command */
|
||||
if ((mac_index < 0) ||
|
||||
(tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
|
||||
(tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
|
||||
(tbl_type.bw != rs_ch_width_from_mac_flags(mac_flags)) ||
|
||||
(tbl_type.ant_type != info->status.antenna) ||
|
||||
(!!(tx_rate & RATE_MCS_HT_MSK) !=
|
||||
!!(mac_flags & IEEE80211_TX_RC_MCS)) ||
|
||||
!!(mac_flags & IEEE80211_TX_RC_MCS)) ||
|
||||
(!!(tx_rate & RATE_MCS_VHT_MSK) !=
|
||||
!!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) ||
|
||||
(!!(tx_rate & RATE_HT_MCS_GF_MSK) !=
|
||||
!!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
|
||||
!!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
|
||||
(rs_index != mac_index)) {
|
||||
IWL_DEBUG_RATE(mvm,
|
||||
"initial rate %d does not match %d (0x%x)\n",
|
||||
|
@ -950,7 +1033,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
|
||||
|
||||
/* Check for invalid LQ type */
|
||||
if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
|
||||
if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_ht(tbl->lq_type) &&
|
||||
!(is_vht(tbl->lq_type)))) {
|
||||
tbl->expected_tpt = expected_tpt_legacy;
|
||||
return;
|
||||
}
|
||||
|
@ -961,18 +1045,40 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
return;
|
||||
}
|
||||
|
||||
ht_tbl_pointer = expected_tpt_mimo2_20MHz;
|
||||
/* Choose among many HT tables depending on number of streams
|
||||
* (SISO/MIMO2), channel width (20/40), SGI, and aggregation
|
||||
* (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation
|
||||
* status */
|
||||
if (is_siso(tbl->lq_type) && !tbl->is_ht40)
|
||||
ht_tbl_pointer = expected_tpt_siso_20MHz;
|
||||
else if (is_siso(tbl->lq_type))
|
||||
ht_tbl_pointer = expected_tpt_siso_40MHz;
|
||||
else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40)
|
||||
ht_tbl_pointer = expected_tpt_mimo2_20MHz;
|
||||
else {
|
||||
WARN_ON_ONCE(!is_mimo2(tbl->lq_type));
|
||||
ht_tbl_pointer = expected_tpt_mimo2_40MHz;
|
||||
if (is_siso(tbl->lq_type)) {
|
||||
switch (tbl->bw) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
ht_tbl_pointer = expected_tpt_siso_20MHz;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_40:
|
||||
ht_tbl_pointer = expected_tpt_siso_40MHz;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
ht_tbl_pointer = expected_tpt_siso_80MHz;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
} else if (is_mimo2(tbl->lq_type)) {
|
||||
switch (tbl->bw) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
ht_tbl_pointer = expected_tpt_mimo2_20MHz;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_40:
|
||||
ht_tbl_pointer = expected_tpt_mimo2_40MHz;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
ht_tbl_pointer = expected_tpt_mimo2_80MHz;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
} else {
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */
|
||||
|
@ -1087,11 +1193,6 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
|
|||
return new_rate;
|
||||
}
|
||||
|
||||
static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta)
|
||||
{
|
||||
return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
|
||||
}
|
||||
|
||||
/* Move to the next action and wrap around to the first action in case
|
||||
* we're at the last action. Assumes actions start at 0.
|
||||
*/
|
||||
|
@ -1105,6 +1206,36 @@ static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl,
|
|||
tbl->action = (tbl->action + 1) % (last_action + 1);
|
||||
}
|
||||
|
||||
static void rs_set_bw_from_sta(struct iwl_scale_tbl_info *tbl,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
|
||||
tbl->bw = RATE_MCS_CHAN_WIDTH_80;
|
||||
else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
|
||||
tbl->bw = RATE_MCS_CHAN_WIDTH_40;
|
||||
else
|
||||
tbl->bw = RATE_MCS_CHAN_WIDTH_20;
|
||||
}
|
||||
|
||||
static bool rs_sgi_allowed(struct iwl_scale_tbl_info *tbl,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
||||
|
||||
if (is_ht20(tbl) && (ht_cap->cap &
|
||||
IEEE80211_HT_CAP_SGI_20))
|
||||
return true;
|
||||
if (is_ht40(tbl) && (ht_cap->cap &
|
||||
IEEE80211_HT_CAP_SGI_40))
|
||||
return true;
|
||||
if (is_ht80(tbl) && (vht_cap->cap &
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up search table for MIMO2
|
||||
*/
|
||||
|
@ -1129,16 +1260,12 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
|
|||
|
||||
IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
|
||||
|
||||
tbl->lq_type = LQ_MIMO2;
|
||||
tbl->lq_type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
|
||||
tbl->action = 0;
|
||||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
rate_mask = lq_sta->active_mimo2_rate;
|
||||
|
||||
if (iwl_is_ht40_tx_allowed(sta))
|
||||
tbl->is_ht40 = 1;
|
||||
else
|
||||
tbl->is_ht40 = 0;
|
||||
|
||||
rs_set_bw_from_sta(tbl, sta);
|
||||
rs_set_expected_tpt_table(lq_sta, tbl);
|
||||
|
||||
rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
|
||||
|
@ -1174,19 +1301,15 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm,
|
|||
|
||||
IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n");
|
||||
|
||||
tbl->lq_type = LQ_SISO;
|
||||
tbl->lq_type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
|
||||
tbl->action = 0;
|
||||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
rate_mask = lq_sta->active_siso_rate;
|
||||
|
||||
if (iwl_is_ht40_tx_allowed(sta))
|
||||
tbl->is_ht40 = 1;
|
||||
else
|
||||
tbl->is_ht40 = 0;
|
||||
|
||||
if (is_green)
|
||||
tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
|
||||
|
||||
rs_set_bw_from_sta(tbl, sta);
|
||||
rs_set_expected_tpt_table(lq_sta, tbl);
|
||||
rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
|
||||
|
||||
|
@ -1313,7 +1436,6 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
|
|||
struct iwl_scale_tbl_info *search_tbl =
|
||||
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
|
||||
struct iwl_rate_scale_data *window = &(tbl->win[index]);
|
||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
|
@ -1385,11 +1507,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
|
|||
goto out;
|
||||
break;
|
||||
case IWL_SISO_SWITCH_GI:
|
||||
if (!tbl->is_ht40 && !(ht_cap->cap &
|
||||
IEEE80211_HT_CAP_SGI_20))
|
||||
break;
|
||||
if (tbl->is_ht40 && !(ht_cap->cap &
|
||||
IEEE80211_HT_CAP_SGI_40))
|
||||
if (!rs_sgi_allowed(tbl, sta))
|
||||
break;
|
||||
|
||||
IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n");
|
||||
|
@ -1445,7 +1563,6 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
|
|||
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
|
||||
struct iwl_scale_tbl_info *search_tbl =
|
||||
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
|
||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
|
@ -1502,11 +1619,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
|
|||
break;
|
||||
|
||||
case IWL_MIMO2_SWITCH_GI:
|
||||
if (!tbl->is_ht40 && !(ht_cap->cap &
|
||||
IEEE80211_HT_CAP_SGI_20))
|
||||
break;
|
||||
if (tbl->is_ht40 && !(ht_cap->cap &
|
||||
IEEE80211_HT_CAP_SGI_40))
|
||||
if (!rs_sgi_allowed(tbl, sta))
|
||||
break;
|
||||
|
||||
IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n");
|
||||
|
@ -2167,7 +2280,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
|
|||
struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct iwl_lq_sta *lq_sta = mvm_sta;
|
||||
int rate_idx;
|
||||
|
||||
IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n");
|
||||
|
||||
|
@ -2192,36 +2304,9 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
|
|||
if (rate_control_send_low(sta, mvm_sta, txrc))
|
||||
return;
|
||||
|
||||
rate_idx = lq_sta->last_txrate_idx;
|
||||
iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags,
|
||||
info->band, &info->control.rates[0]);
|
||||
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
|
||||
rate_idx -= IWL_FIRST_OFDM_RATE;
|
||||
/* 6M and 9M shared same MCS index */
|
||||
rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
|
||||
WARN_ON_ONCE(rs_extract_rate(lq_sta->last_rate_n_flags) >=
|
||||
IWL_RATE_MIMO3_6M_PLCP);
|
||||
if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
|
||||
IWL_RATE_MIMO2_6M_PLCP)
|
||||
rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
|
||||
info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||
if (lq_sta->last_rate_n_flags & RATE_HT_MCS_GF_MSK)
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
||||
} else {
|
||||
/* Check for invalid rates */
|
||||
if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
|
||||
((sband->band == IEEE80211_BAND_5GHZ) &&
|
||||
(rate_idx < IWL_FIRST_OFDM_RATE)))
|
||||
rate_idx = rate_lowest_index(sband, sta);
|
||||
/* On valid 5 GHz rate, adjust index */
|
||||
else if (sband->band == IEEE80211_BAND_5GHZ)
|
||||
rate_idx -= IWL_FIRST_OFDM_RATE;
|
||||
info->control.rates[0].flags = 0;
|
||||
}
|
||||
info->control.rates[0].idx = rate_idx;
|
||||
info->control.rates[0].count = 1;
|
||||
}
|
||||
|
||||
|
@ -2238,6 +2323,24 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
|
|||
return &sta_priv->lq_sta;
|
||||
}
|
||||
|
||||
static int rs_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap,
|
||||
int nss)
|
||||
{
|
||||
u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
|
||||
(0x3 << (2 * (nss - 1)));
|
||||
rx_mcs >>= (2 * (nss - 1));
|
||||
|
||||
if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_7)
|
||||
return IWL_RATE_MCS_7_INDEX;
|
||||
else if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_8)
|
||||
return IWL_RATE_MCS_8_INDEX;
|
||||
else if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_9)
|
||||
return IWL_RATE_MCS_9_INDEX;
|
||||
|
||||
WARN_ON_ONCE(rx_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after adding a new station to initialize rate scaling
|
||||
*/
|
||||
|
@ -2247,6 +2350,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
int i, j;
|
||||
struct ieee80211_hw *hw = mvm->hw;
|
||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
||||
struct iwl_mvm_sta *sta_priv;
|
||||
struct iwl_lq_sta *lq_sta;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
@ -2285,25 +2389,54 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
for_each_set_bit(i, &supp, BITS_PER_LONG)
|
||||
lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
|
||||
|
||||
/*
|
||||
* active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
|
||||
* supp_rates[] does not; shift to convert format, force 9 MBits off.
|
||||
*/
|
||||
lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
|
||||
lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
|
||||
lq_sta->active_siso_rate &= ~((u16)0x2);
|
||||
lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
|
||||
/* TODO: should probably account for rx_highest for both HT/VHT */
|
||||
if (!vht_cap || !vht_cap->vht_supported) {
|
||||
/* active_siso_rate mask includes 9 MBits (bit 5),
|
||||
* and CCK (bits 0-3), supp_rates[] does not;
|
||||
* shift to convert format, force 9 MBits off.
|
||||
*/
|
||||
lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
|
||||
lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
|
||||
lq_sta->active_siso_rate &= ~((u16)0x2);
|
||||
lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
|
||||
|
||||
/* Same here */
|
||||
lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
|
||||
lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
|
||||
lq_sta->active_mimo2_rate &= ~((u16)0x2);
|
||||
lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
|
||||
/* Same here */
|
||||
lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
|
||||
lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
|
||||
lq_sta->active_mimo2_rate &= ~((u16)0x2);
|
||||
lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
|
||||
|
||||
lq_sta->is_vht = false;
|
||||
} else {
|
||||
int highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 1);
|
||||
if (highest_mcs >= IWL_RATE_MCS_0_INDEX) {
|
||||
for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) {
|
||||
if (i == IWL_RATE_9M_INDEX)
|
||||
continue;
|
||||
|
||||
lq_sta->active_siso_rate |= BIT(i);
|
||||
}
|
||||
}
|
||||
|
||||
highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2);
|
||||
if (highest_mcs >= IWL_RATE_MCS_0_INDEX) {
|
||||
for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) {
|
||||
if (i == IWL_RATE_9M_INDEX)
|
||||
continue;
|
||||
|
||||
lq_sta->active_mimo2_rate |= BIT(i);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: avoid MCS9 in 20Mhz which isn't valid for 11ac */
|
||||
lq_sta->is_vht = true;
|
||||
}
|
||||
|
||||
IWL_DEBUG_RATE(mvm,
|
||||
"SISO-RATE=%X MIMO2-RATE=%X\n",
|
||||
"SISO-RATE=%X MIMO2-RATE=%X VHT=%d\n",
|
||||
lq_sta->active_siso_rate,
|
||||
lq_sta->active_mimo2_rate);
|
||||
lq_sta->active_mimo2_rate,
|
||||
lq_sta->is_vht);
|
||||
|
||||
/* These values will be overridden later */
|
||||
lq_sta->lq.single_stream_ant_msk =
|
||||
|
@ -2406,7 +2539,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
|
|||
rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
|
||||
&rate_idx);
|
||||
|
||||
|
||||
/* Indicate to uCode which entries might be MIMO.
|
||||
* If initial rate was MIMO, this will finally end up
|
||||
* as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
|
||||
|
@ -2432,7 +2564,9 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
/* Don't allow HT rates after next pass.
|
||||
* rs_get_lower_rate() will change type to LQ_A or LQ_G. */
|
||||
* rs_get_lower_rate() will change type to LQ_LEGACY_A
|
||||
* or LQ_LEGACY_G.
|
||||
*/
|
||||
use_ht_possible = 0;
|
||||
|
||||
/* Override next rate if needed for debug purposes */
|
||||
|
@ -2563,12 +2697,15 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
(iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "",
|
||||
(iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : "");
|
||||
desc += sprintf(buff+desc, "lq type %s\n",
|
||||
(is_legacy(tbl->lq_type)) ? "legacy" : "HT");
|
||||
if (is_Ht(tbl->lq_type)) {
|
||||
(is_legacy(tbl->lq_type)) ? "legacy" :
|
||||
is_vht(tbl->lq_type) ? "VHT" : "HT");
|
||||
if (is_ht(tbl->lq_type)) {
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
(is_siso(tbl->lq_type)) ? "SISO" : "MIMO2");
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
(tbl->is_ht40) ? "40MHz" : "20MHz");
|
||||
(is_ht20(tbl)) ? "20MHz" :
|
||||
(is_ht40(tbl)) ? "40MHz" :
|
||||
(is_ht80(tbl)) ? "80Mhz" : "BAD BW");
|
||||
desc += sprintf(buff+desc, " %s %s %s\n",
|
||||
(tbl->is_SGI) ? "SGI" : "",
|
||||
(lq_sta->is_green) ? "GF enabled" : "",
|
||||
|
@ -2630,7 +2767,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
|
|||
int desc = 0;
|
||||
int i, j;
|
||||
ssize_t ret;
|
||||
|
||||
struct iwl_scale_tbl_info *tbl;
|
||||
struct iwl_lq_sta *lq_sta = file->private_data;
|
||||
|
||||
buff = kmalloc(1024, GFP_KERNEL);
|
||||
|
@ -2638,21 +2775,24 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
|
|||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < LQ_SIZE; i++) {
|
||||
tbl = &(lq_sta->lq_info[i]);
|
||||
desc += sprintf(buff+desc,
|
||||
"%s type=%d SGI=%d HT40=%d DUP=0 GF=%d\n"
|
||||
"%s type=%d SGI=%d BW=%s DUP=0 GF=%d\n"
|
||||
"rate=0x%X\n",
|
||||
lq_sta->active_tbl == i ? "*" : "x",
|
||||
lq_sta->lq_info[i].lq_type,
|
||||
lq_sta->lq_info[i].is_SGI,
|
||||
lq_sta->lq_info[i].is_ht40,
|
||||
tbl->lq_type,
|
||||
tbl->is_SGI,
|
||||
is_ht20(tbl) ? "20Mhz" :
|
||||
is_ht40(tbl) ? "40Mhz" :
|
||||
is_ht80(tbl) ? "80Mhz" : "ERR",
|
||||
lq_sta->is_green,
|
||||
lq_sta->lq_info[i].current_rate);
|
||||
tbl->current_rate);
|
||||
for (j = 0; j < IWL_RATE_COUNT; j++) {
|
||||
desc += sprintf(buff+desc,
|
||||
"counter=%d success=%d %%=%d\n",
|
||||
lq_sta->lq_info[i].win[j].counter,
|
||||
lq_sta->lq_info[i].win[j].success_counter,
|
||||
lq_sta->lq_info[i].win[j].success_ratio);
|
||||
tbl->win[j].counter,
|
||||
tbl->win[j].success_counter,
|
||||
tbl->win[j].success_ratio);
|
||||
}
|
||||
}
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
|
||||
|
|
|
@ -35,9 +35,11 @@
|
|||
#include "iwl-trans.h"
|
||||
|
||||
struct iwl_rs_rate_info {
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
|
||||
u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 plcp_ht_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
|
||||
u8 plcp_ht_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
|
||||
u8 plcp_vht_siso;
|
||||
u8 plcp_vht_mimo2;
|
||||
u8 prev_rs; /* previous rate used in rs algo */
|
||||
u8 next_rs; /* next rate used in rs algo */
|
||||
};
|
||||
|
@ -83,35 +85,52 @@ enum {
|
|||
#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX)
|
||||
|
||||
|
||||
/* uCode API values for OFDM high-throughput (HT) bit rates */
|
||||
/* uCode API values for HT/VHT bit rates */
|
||||
enum {
|
||||
IWL_RATE_SISO_6M_PLCP = 0,
|
||||
IWL_RATE_SISO_12M_PLCP = 1,
|
||||
IWL_RATE_SISO_18M_PLCP = 2,
|
||||
IWL_RATE_SISO_24M_PLCP = 3,
|
||||
IWL_RATE_SISO_36M_PLCP = 4,
|
||||
IWL_RATE_SISO_48M_PLCP = 5,
|
||||
IWL_RATE_SISO_54M_PLCP = 6,
|
||||
IWL_RATE_SISO_60M_PLCP = 7,
|
||||
IWL_RATE_MIMO2_6M_PLCP = 0x8,
|
||||
IWL_RATE_MIMO2_12M_PLCP = 0x9,
|
||||
IWL_RATE_MIMO2_18M_PLCP = 0xa,
|
||||
IWL_RATE_MIMO2_24M_PLCP = 0xb,
|
||||
IWL_RATE_MIMO2_36M_PLCP = 0xc,
|
||||
IWL_RATE_MIMO2_48M_PLCP = 0xd,
|
||||
IWL_RATE_MIMO2_54M_PLCP = 0xe,
|
||||
IWL_RATE_MIMO2_60M_PLCP = 0xf,
|
||||
IWL_RATE_MIMO3_6M_PLCP = 0x10,
|
||||
IWL_RATE_MIMO3_12M_PLCP = 0x11,
|
||||
IWL_RATE_MIMO3_18M_PLCP = 0x12,
|
||||
IWL_RATE_MIMO3_24M_PLCP = 0x13,
|
||||
IWL_RATE_MIMO3_36M_PLCP = 0x14,
|
||||
IWL_RATE_MIMO3_48M_PLCP = 0x15,
|
||||
IWL_RATE_MIMO3_54M_PLCP = 0x16,
|
||||
IWL_RATE_MIMO3_60M_PLCP = 0x17,
|
||||
IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_HT_SISO_MCS_0_PLCP = 0,
|
||||
IWL_RATE_HT_SISO_MCS_1_PLCP = 1,
|
||||
IWL_RATE_HT_SISO_MCS_2_PLCP = 2,
|
||||
IWL_RATE_HT_SISO_MCS_3_PLCP = 3,
|
||||
IWL_RATE_HT_SISO_MCS_4_PLCP = 4,
|
||||
IWL_RATE_HT_SISO_MCS_5_PLCP = 5,
|
||||
IWL_RATE_HT_SISO_MCS_6_PLCP = 6,
|
||||
IWL_RATE_HT_SISO_MCS_7_PLCP = 7,
|
||||
IWL_RATE_HT_MIMO2_MCS_0_PLCP = 0x8,
|
||||
IWL_RATE_HT_MIMO2_MCS_1_PLCP = 0x9,
|
||||
IWL_RATE_HT_MIMO2_MCS_2_PLCP = 0xA,
|
||||
IWL_RATE_HT_MIMO2_MCS_3_PLCP = 0xB,
|
||||
IWL_RATE_HT_MIMO2_MCS_4_PLCP = 0xC,
|
||||
IWL_RATE_HT_MIMO2_MCS_5_PLCP = 0xD,
|
||||
IWL_RATE_HT_MIMO2_MCS_6_PLCP = 0xE,
|
||||
IWL_RATE_HT_MIMO2_MCS_7_PLCP = 0xF,
|
||||
IWL_RATE_VHT_SISO_MCS_0_PLCP = 0,
|
||||
IWL_RATE_VHT_SISO_MCS_1_PLCP = 1,
|
||||
IWL_RATE_VHT_SISO_MCS_2_PLCP = 2,
|
||||
IWL_RATE_VHT_SISO_MCS_3_PLCP = 3,
|
||||
IWL_RATE_VHT_SISO_MCS_4_PLCP = 4,
|
||||
IWL_RATE_VHT_SISO_MCS_5_PLCP = 5,
|
||||
IWL_RATE_VHT_SISO_MCS_6_PLCP = 6,
|
||||
IWL_RATE_VHT_SISO_MCS_7_PLCP = 7,
|
||||
IWL_RATE_VHT_SISO_MCS_8_PLCP = 8,
|
||||
IWL_RATE_VHT_SISO_MCS_9_PLCP = 9,
|
||||
IWL_RATE_VHT_MIMO2_MCS_0_PLCP = 0x10,
|
||||
IWL_RATE_VHT_MIMO2_MCS_1_PLCP = 0x11,
|
||||
IWL_RATE_VHT_MIMO2_MCS_2_PLCP = 0x12,
|
||||
IWL_RATE_VHT_MIMO2_MCS_3_PLCP = 0x13,
|
||||
IWL_RATE_VHT_MIMO2_MCS_4_PLCP = 0x14,
|
||||
IWL_RATE_VHT_MIMO2_MCS_5_PLCP = 0x15,
|
||||
IWL_RATE_VHT_MIMO2_MCS_6_PLCP = 0x16,
|
||||
IWL_RATE_VHT_MIMO2_MCS_7_PLCP = 0x17,
|
||||
IWL_RATE_VHT_MIMO2_MCS_8_PLCP = 0x18,
|
||||
IWL_RATE_VHT_MIMO2_MCS_9_PLCP = 0x19,
|
||||
IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_VHT_SISO_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_VHT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_SISO_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_SISO_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_MIMO2_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_MIMO2_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
};
|
||||
|
||||
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
|
||||
|
@ -196,20 +215,31 @@ enum {
|
|||
|
||||
enum iwl_table_type {
|
||||
LQ_NONE,
|
||||
LQ_G, /* legacy types */
|
||||
LQ_A,
|
||||
LQ_SISO, /* high-throughput types */
|
||||
LQ_MIMO2,
|
||||
LQ_LEGACY_G, /* legacy types */
|
||||
LQ_LEGACY_A,
|
||||
LQ_HT_SISO, /* HT types */
|
||||
LQ_HT_MIMO2,
|
||||
LQ_VHT_SISO, /* VHT types */
|
||||
LQ_VHT_MIMO2,
|
||||
LQ_MAX,
|
||||
};
|
||||
|
||||
#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
|
||||
#define is_siso(tbl) ((tbl) == LQ_SISO)
|
||||
#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
|
||||
#define is_mimo(tbl) is_mimo2(tbl)
|
||||
#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
|
||||
#define is_a_band(tbl) ((tbl) == LQ_A)
|
||||
#define is_g_and(tbl) ((tbl) == LQ_G)
|
||||
#define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A))
|
||||
#define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO)
|
||||
#define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2)
|
||||
#define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO)
|
||||
#define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2)
|
||||
#define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl))
|
||||
#define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl))
|
||||
#define is_mimo(tbl) (is_mimo2(tbl))
|
||||
#define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl))
|
||||
#define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl))
|
||||
#define is_a_band(tbl) ((tbl) == LQ_LEGACY_A)
|
||||
#define is_g_band(tbl) ((tbl) == LQ_LEGACY_G)
|
||||
|
||||
#define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20)
|
||||
#define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40)
|
||||
#define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80)
|
||||
|
||||
#define IWL_MAX_MCS_DISPLAY_SIZE 12
|
||||
|
||||
|
@ -240,7 +270,7 @@ struct iwl_scale_tbl_info {
|
|||
enum iwl_table_type lq_type;
|
||||
u8 ant_type;
|
||||
u8 is_SGI; /* 1 = short guard interval */
|
||||
u8 is_ht40; /* 1 = 40 MHz channel width */
|
||||
u32 bw; /* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */
|
||||
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
|
||||
u8 max_search; /* maximun number of tables we can search */
|
||||
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
|
||||
|
@ -271,6 +301,7 @@ struct iwl_lq_sta {
|
|||
|
||||
u8 action_counter; /* # mode-switch actions tried */
|
||||
u8 is_green;
|
||||
bool is_vht;
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
|
||||
|
|
|
@ -511,16 +511,10 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status)
|
|||
}
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
/**
|
||||
* translate ucode response to mac80211 tx status control values
|
||||
*/
|
||||
static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
|
||||
struct ieee80211_tx_info *info)
|
||||
void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_tx_rate *r)
|
||||
{
|
||||
struct ieee80211_tx_rate *r = &info->status.rates[0];
|
||||
|
||||
info->status.antenna =
|
||||
((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
|
||||
if (rate_n_flags & RATE_HT_MCS_GF_MSK)
|
||||
r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
|
@ -549,10 +543,23 @@ static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
|
|||
r->flags |= IEEE80211_TX_RC_VHT_MCS;
|
||||
} else {
|
||||
r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
|
||||
info->band);
|
||||
band);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* translate ucode response to mac80211 tx status control values
|
||||
*/
|
||||
static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags,
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
struct ieee80211_tx_rate *r = &info->status.rates[0];
|
||||
|
||||
info->status.antenna =
|
||||
((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
|
||||
iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r);
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
|
@ -602,8 +609,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate),
|
||||
info);
|
||||
iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
|
||||
info);
|
||||
|
||||
/* Single frame failure in an AMPDU queue => send BAR */
|
||||
if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE &&
|
||||
|
@ -900,8 +907,8 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
|||
info->flags |= IEEE80211_TX_STAT_AMPDU;
|
||||
info->status.ampdu_ack_len = ba_notif->txed_2_done;
|
||||
info->status.ampdu_len = ba_notif->txed;
|
||||
iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags,
|
||||
info);
|
||||
iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
|
||||
info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue