blob: 19e7ed94e1e832f4a4ca09d40142bc27614296df [file] [log] [blame]
/******************************************************************************
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "_rateScaleMng.h"
#define BOOLEAN bool
#define SHIFT_AND_MASK(val, mask, pos) (((val) >> (pos)) & ((mask) >> (pos)))
#define SEC_TO_USEC(x) ((x)*USEC_PER_SEC)
#define MSEC_TO_USEC(x) ((x)*USEC_PER_MSEC)
#define _memclr(p, s) (memset((p), 0, (s)))
#define DBG_PRINTF(...)
#define NON_SHARED_ANT_RFIC_ID (staInfo->mvm->cfg->non_shared_ant == ANT_A ? 0 : 1)
#define BT_COEX_SHARED_ANT_ID (staInfo->mvm->cfg->non_shared_ant ^ ANT_AB)
#define PWR_IS_SLEEP_ALLOWED (!staInfo->mvm->ps_disabled)
#define MSB2ORD msb2ord
#define LSB2ORD lsb2ord
static inline unsigned long msb2ord(unsigned long x) { return find_last_bit(&x, BITS_PER_LONG); }
static inline unsigned long lsb2ord(unsigned long x) { return find_first_bit(&x, BITS_PER_LONG); }
// TODO - move to coex.c
static bool btCoexManagerIsAntAvailable(struct iwl_mvm* mvm, uint8_t ant) {
if (mvm->cfg->bt_shared_single_ant) {
return true;
}
if (!(ant & ~mvm->cfg->non_shared_ant)) {
return true;
}
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
}
static bool btCoexManagerBtOwnsAnt(struct iwl_mvm* mvm) {
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= BT_HIGH_TRAFFIC;
}
typedef struct _TLC_STAT_COMMON_API_S {
/* @brief number of packets sent
* txed[0] - rate index 0
* txed[1] - rate index != 0
*/
U16 txed[2];
/**
* @brief number of packets we got acknowledgment for packet sent
* acked[0] - rate index 0
* acked[1] - rate index != 0
*/
U16 acked[2];
/* Number of frames we got BA response for (regardless of success) */
U16 trafficLoad;
U16 baTxed;
U16 baAcked;
} TLC_STAT_COMMON_API_S;
static const U08 RS_NON_HT_RATE_TO_API_RATE[] = {
[RS_NON_HT_RATE_CCK_1M] = R_1M, [RS_NON_HT_RATE_CCK_2M] = R_2M,
[RS_NON_HT_RATE_CCK_5_5M] = R_5_5M, [RS_NON_HT_RATE_CCK_11M] = R_11M,
[RS_NON_HT_RATE_OFDM_6M] = R_6M, [RS_NON_HT_RATE_OFDM_9M] = R_9M,
[RS_NON_HT_RATE_OFDM_12M] = R_12M, [RS_NON_HT_RATE_OFDM_18M] = R_18M,
[RS_NON_HT_RATE_OFDM_24M] = R_24M, [RS_NON_HT_RATE_OFDM_36M] = R_36M,
[RS_NON_HT_RATE_OFDM_48M] = R_48M, [RS_NON_HT_RATE_OFDM_54M] = R_54M,
};
// This array converts VHT rate configuration to phy rate
// See ieee80211-2016 spec, section 21.4 tabled for reference values
// Note the values are in bps, instead of mbps (i.e. multiplied by 2^20)
// The table access is rsMngVhtRateToBps[BW][MSC].
static const U32 rsMngVhtRateToBps[][10] = {
[CHANNEL_WIDTH20] = {6815744, 13631488, 20447232, 27262976, 40894464, 54525952, 61341696,
68157440, 81788928, 90701824},
[CHANNEL_WIDTH40] = {14155776, 28311552, 42467328, 56623104, 84934656, 113246208, 127401984,
141557760, 169869312, 188743680},
[CHANNEL_WIDTH80] = {30723277 /*rounded*/, 61341696, 92064973 /*rounded*/, 122683392, 184025088,
245366784, 276090061 /*rounded*/, 306708480, 368050176, 408944640},
[CHANNEL_WIDTH160] = {61341696, 122683392, 184025088, 245366784, 368050176, 490733568,
552075264, 613416960, 736100352, 817889280},
};
// The array cell index is the MCS. e.g. - cell 0 - MCS0 6M. etc.
static const U08 downColMcsToLegacy[] = {
[RS_MCS_0_HE_ER_AND_DCM] = RS_NON_HT_RATE_OFDM_6M,
[RS_MCS_0] = RS_NON_HT_RATE_OFDM_6M,
[RS_MCS_1] = RS_NON_HT_RATE_OFDM_12M,
[RS_MCS_2] = RS_NON_HT_RATE_OFDM_18M,
[RS_MCS_3] = RS_NON_HT_RATE_OFDM_24M,
[RS_MCS_4] = RS_NON_HT_RATE_OFDM_36M,
[RS_MCS_5] = RS_NON_HT_RATE_OFDM_48M,
[RS_MCS_6] = RS_NON_HT_RATE_OFDM_54M,
[RS_MCS_7] = RS_NON_HT_RATE_OFDM_54M,
[RS_MCS_8] = RS_NON_HT_RATE_OFDM_54M,
[RS_MCS_9] = RS_NON_HT_RATE_OFDM_54M,
[RS_MCS_10] = RS_NON_HT_RATE_OFDM_54M,
[RS_MCS_11] = RS_NON_HT_RATE_OFDM_54M,
};
typedef struct _RS_MNG_DYN_BW_STAY {
RS_MCS_E lowestStayMcs;
RS_MCS_E highestStayMcs;
} RS_MNG_DYN_BW_STAY;
#define RS_MNG_DYN_BW_STAY_MCS(_bw, _nss1min, _nss1max, _nss2min, _nss2max) \
[CHANNEL_WIDTH## \
_bw] = {{.lowestStayMcs = RS_MCS_##_nss1min, .highestStayMcs = RS_MCS_##_nss1max}, \
{.lowestStayMcs = RS_MCS_##_nss2min, .highestStayMcs = RS_MCS_##_nss2max}}
// thresholds above/below which bandwidth will be increase/decreased
static RS_MNG_DYN_BW_STAY g_rsMngDynBwStayMcs[][2] = {
RS_MNG_DYN_BW_STAY_MCS(20, 0, 1, 0, 1), RS_MNG_DYN_BW_STAY_MCS(40, 2, 2, 2, 2),
RS_MNG_DYN_BW_STAY_MCS(80, 5, 8, 4, 7), RS_MNG_DYN_BW_STAY_MCS(160, 7, 9, 6, 9)};
/***********************************************************************/
/*
* The following tables contain the expected throughput metrics for all rates
*
* 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
*
* where invalid entries are zeros.
*
* CCK rates are only valid in legacy table and will only be used in G
* (2.4 GHz) band.
*/
static const TPT_BY_RATE_ARR expectedTptNonHt = {
[RS_NON_HT_RATE_CCK_1M] = 7, [RS_NON_HT_RATE_CCK_2M] = 12,
[RS_NON_HT_RATE_CCK_5_5M] = 33, [RS_NON_HT_RATE_CCK_11M] = 54,
[RS_NON_HT_RATE_OFDM_6M] = 38, [RS_NON_HT_RATE_OFDM_9M] = 58,
[RS_NON_HT_RATE_OFDM_12M] = 76, [RS_NON_HT_RATE_OFDM_18M] = 108,
[RS_NON_HT_RATE_OFDM_24M] = 135, [RS_NON_HT_RATE_OFDM_36M] = 176,
[RS_NON_HT_RATE_OFDM_48M] = 208, [RS_NON_HT_RATE_OFDM_54M] = 221,
};
static const TPT_BY_RATE_ARR expectedTptHtVht[2][MAX_CHANNEL_BW_INDX][2][2] = {
[RS_MNG_NO_AGG] = {
[CHANNEL_WIDTH20] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 49, [RS_MCS_1] = 86, [RS_MCS_2] = 115, [RS_MCS_3] = 140,
[RS_MCS_4] = 178, [RS_MCS_5] = 204, [RS_MCS_6] = 215, [RS_MCS_7] = 223,
[RS_MCS_8] = 240,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 84, [RS_MCS_1] = 136, [RS_MCS_2] = 173, [RS_MCS_3] = 200,
[RS_MCS_4] = 238, [RS_MCS_5] = 260, [RS_MCS_6] = 267, [RS_MCS_7] = 275,
[RS_MCS_8] = 289,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 53, [RS_MCS_1] = 93, [RS_MCS_2] = 124, [RS_MCS_3] = 149,
[RS_MCS_4] = 188, [RS_MCS_5] = 214, [RS_MCS_6] = 225, [RS_MCS_7] = 233,
[RS_MCS_8] = 249,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 91, [RS_MCS_1] = 144, [RS_MCS_2] = 182, [RS_MCS_3] = 210,
[RS_MCS_4] = 246, [RS_MCS_5] = 267, [RS_MCS_6] = 274, [RS_MCS_7] = 282,
[RS_MCS_8] = 295,
},
},
},
[CHANNEL_WIDTH40] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 87, [RS_MCS_1] = 140, [RS_MCS_2] = 177, [RS_MCS_3] = 207,
[RS_MCS_4] = 245, [RS_MCS_5] = 265, [RS_MCS_6] = 273, [RS_MCS_7] = 281,
[RS_MCS_8] = 296, [RS_MCS_9] = 299,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 135, [RS_MCS_1] = 197, [RS_MCS_2] = 234, [RS_MCS_3] = 259,
[RS_MCS_4] = 292, [RS_MCS_5] = 304, [RS_MCS_6] = 311, [RS_MCS_7] = 314,
[RS_MCS_8] = 321, [RS_MCS_9] = 331,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 94, [RS_MCS_1] = 149, [RS_MCS_2] = 187, [RS_MCS_3] = 216,
[RS_MCS_4] = 253, [RS_MCS_5] = 273, [RS_MCS_6] = 280, [RS_MCS_7] = 288,
[RS_MCS_8] = 302, [RS_MCS_9] = 305,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 144, [RS_MCS_1] = 205, [RS_MCS_2] = 242, [RS_MCS_3] = 266,
[RS_MCS_4] = 297, [RS_MCS_5] = 309, [RS_MCS_6] = 315, [RS_MCS_7] = 318,
[RS_MCS_8] = 325, [RS_MCS_9] = 335,
},
},
},
[CHANNEL_WIDTH80] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 142, [RS_MCS_1] = 205, [RS_MCS_2] = 240, [RS_MCS_3] = 267,
[RS_MCS_4] = 299, [RS_MCS_5] = 312, [RS_MCS_6] = 319, [RS_MCS_7] = 323,
[RS_MCS_8] = 330, [RS_MCS_9] = 334,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 195, [RS_MCS_1] = 251, [RS_MCS_2] = 283, [RS_MCS_3] = 303,
[RS_MCS_4] = 325, [RS_MCS_5] = 333, [RS_MCS_6] = 337, [RS_MCS_7] = 337,
[RS_MCS_8] = 341, [RS_MCS_9] = 345,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 151, [RS_MCS_1] = 213, [RS_MCS_2] = 248, [RS_MCS_3] = 274,
[RS_MCS_4] = 305, [RS_MCS_5] = 317, [RS_MCS_6] = 323, [RS_MCS_7] = 327,
[RS_MCS_8] = 334, [RS_MCS_9] = 337,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 203, [RS_MCS_1] = 258, [RS_MCS_2] = 288, [RS_MCS_3] = 308,
[RS_MCS_4] = 328, [RS_MCS_5] = 335, [RS_MCS_6] = 339, [RS_MCS_7] = 339,
[RS_MCS_8] = 343, [RS_MCS_9] = 346,
},
},
},
[CHANNEL_WIDTH160] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 197, [RS_MCS_1] = 254, [RS_MCS_2] = 287, [RS_MCS_3] = 307,
[RS_MCS_4] = 330, [RS_MCS_5] = 338, [RS_MCS_6] = 342, [RS_MCS_7] = 342,
[RS_MCS_8] = 346, [RS_MCS_9] = 350,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 239, [RS_MCS_1] = 286, [RS_MCS_2] = 311, [RS_MCS_3] = 327,
[RS_MCS_4] = 341, [RS_MCS_5] = 345, [RS_MCS_6] = 349, [RS_MCS_7] = 349,
[RS_MCS_8] = 349, [RS_MCS_9] = 353,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 205, [RS_MCS_1] = 261, [RS_MCS_2] = 292, [RS_MCS_3] = 312,
[RS_MCS_4] = 334, [RS_MCS_5] = 341, [RS_MCS_6] = 345, [RS_MCS_7] = 345,
[RS_MCS_8] = 348, [RS_MCS_9] = 352,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 245, [RS_MCS_1] = 290, [RS_MCS_2] = 314, [RS_MCS_3] = 330,
[RS_MCS_4] = 343, [RS_MCS_5] = 346, [RS_MCS_6] = 350, [RS_MCS_7] = 350,
[RS_MCS_8] = 350, [RS_MCS_9] = 354,
},
},
},
},
[RS_MNG_AGG] = {
[CHANNEL_WIDTH20] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 53, [RS_MCS_1] = 106, [RS_MCS_2] = 159, [RS_MCS_3] = 213,
[RS_MCS_4] = 319, [RS_MCS_5] = 426, [RS_MCS_6] = 481, [RS_MCS_7] = 534,
[RS_MCS_8] = 641,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 105, [RS_MCS_1] = 211, [RS_MCS_2] = 318, [RS_MCS_3] = 425,
[RS_MCS_4] = 640, [RS_MCS_5] = 846, [RS_MCS_6] = 951, [RS_MCS_7] = 1060,
[RS_MCS_8] = 1266,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 58, [RS_MCS_1] = 116, [RS_MCS_2] = 177, [RS_MCS_3] = 237,
[RS_MCS_4] = 356, [RS_MCS_5] = 474, [RS_MCS_6] = 534, [RS_MCS_7] = 593,
[RS_MCS_8] = 712,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 116, [RS_MCS_1] = 235, [RS_MCS_2] = 354, [RS_MCS_3] = 472,
[RS_MCS_4] = 712, [RS_MCS_5] = 942, [RS_MCS_6] = 1058, [RS_MCS_7] = 1175,
[RS_MCS_8] = 1401,
},
},
},
[CHANNEL_WIDTH40] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 109, [RS_MCS_1] = 219, [RS_MCS_2] = 331, [RS_MCS_3] = 442,
[RS_MCS_4] = 665, [RS_MCS_5] = 882, [RS_MCS_6] = 991, [RS_MCS_7] = 1103,
[RS_MCS_8] = 1316, [RS_MCS_9] = 1450,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 222, [RS_MCS_1] = 445, [RS_MCS_2] = 669, [RS_MCS_3] = 892,
[RS_MCS_4] = 1334, [RS_MCS_5] = 1725, [RS_MCS_6] = 1907, [RS_MCS_7] = 2085,
[RS_MCS_8] = 2422, [RS_MCS_9] = 2637,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 120, [RS_MCS_1] = 244, [RS_MCS_2] = 368, [RS_MCS_3] = 492,
[RS_MCS_4] = 740, [RS_MCS_5] = 978, [RS_MCS_6] = 1101, [RS_MCS_7] = 1222,
[RS_MCS_8] = 1456, [RS_MCS_9] = 1601,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 246, [RS_MCS_1] = 494, [RS_MCS_2] = 742, [RS_MCS_3] = 991,
[RS_MCS_4] = 1470, [RS_MCS_5] = 1888, [RS_MCS_6] = 2085, [RS_MCS_7] = 2276,
[RS_MCS_8] = 2636, [RS_MCS_9] = 2865,
},
},
},
[CHANNEL_WIDTH80] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 237, [RS_MCS_1] = 478, [RS_MCS_2] = 718, [RS_MCS_3] = 959,
[RS_MCS_4] = 1427, [RS_MCS_5] = 1849, [RS_MCS_6] = 2043, [RS_MCS_7] = 2232,
[RS_MCS_8] = 2589, [RS_MCS_9] = 2813,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 475, [RS_MCS_1] = 953, [RS_MCS_2] = 1420, [RS_MCS_3] = 1843,
[RS_MCS_4] = 2584, [RS_MCS_5] = 3229, [RS_MCS_6] = 3522, [RS_MCS_7] = 3799,
[RS_MCS_8] = 4303, [RS_MCS_9] = 4603,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 263, [RS_MCS_1] = 531, [RS_MCS_2] = 797, [RS_MCS_3] = 1065,
[RS_MCS_4] = 1577, [RS_MCS_5] = 2022, [RS_MCS_6] = 2231, [RS_MCS_7] = 2434,
[RS_MCS_8] = 2814, [RS_MCS_9] = 3052,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 528, [RS_MCS_1] = 1058, [RS_MCS_2] = 1569, [RS_MCS_3] = 2016,
[RS_MCS_4] = 2808, [RS_MCS_5] = 3490, [RS_MCS_6] = 3798, [RS_MCS_7] = 4087,
[RS_MCS_8] = 4610, [RS_MCS_9] = 4919,
},
},
},
[CHANNEL_WIDTH160] = {
[RS_MNG_NGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 476, [RS_MCS_1] = 954, [RS_MCS_2] = 1422, [RS_MCS_3] = 1846,
[RS_MCS_4] = 2589, [RS_MCS_5] = 3237, [RS_MCS_6] = 3531, [RS_MCS_7] = 3810,
[RS_MCS_8] = 4317, [RS_MCS_9] = 4619,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 948, [RS_MCS_1] = 1833, [RS_MCS_2] = 2569, [RS_MCS_3] = 3221,
[RS_MCS_4] = 4303, [RS_MCS_5] = 5162, [RS_MCS_6] = 5530, [RS_MCS_7] = 5856,
[RS_MCS_8] = 6449, [RS_MCS_9] = 6767,
},
},
[RS_MNG_SGI] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 529, [RS_MCS_1] = 1060, [RS_MCS_2] = 1571, [RS_MCS_3] = 2019,
[RS_MCS_4] = 2814, [RS_MCS_5] = 3499, [RS_MCS_6] = 3808, [RS_MCS_7] = 4100,
[RS_MCS_8] = 4626, [RS_MCS_9] = 4937,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 1053, [RS_MCS_1] = 2004, [RS_MCS_2] = 2790, [RS_MCS_3] = 3481,
[RS_MCS_4] = 4610, [RS_MCS_5] = 5491, [RS_MCS_6] = 5864, [RS_MCS_7] = 6194,
[RS_MCS_8] = 6787, [RS_MCS_9] = 7103,
},
},
},
},
};
static const TPT_BY_RATE_ARR expectedTptHe[2][MAX_CHANNEL_BW_INDX][3][2] = {
[RS_MNG_NO_AGG] = {
[CHANNEL_WIDTH20] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 30, [RS_MCS_1] = 61, [RS_MCS_2] = 92, [RS_MCS_3] = 122,
[RS_MCS_4] = 184, [RS_MCS_5] = 245, [RS_MCS_6] = 276, [RS_MCS_7] = 307,
[RS_MCS_8] = 368, [RS_MCS_9] = 409, [RS_MCS_10] = 460, [RS_MCS_11] = 511,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 61, [RS_MCS_1] = 122, [RS_MCS_2] = 184, [RS_MCS_3] = 245,
[RS_MCS_4] = 368, [RS_MCS_5] = 491, [RS_MCS_6] = 552, [RS_MCS_7] = 614,
[RS_MCS_8] = 737, [RS_MCS_9] = 819, [RS_MCS_10] = 921, [RS_MCS_11] = 1023,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 34, [RS_MCS_1] = 68, [RS_MCS_2] = 102, [RS_MCS_3] = 136,
[RS_MCS_4] = 204, [RS_MCS_5] = 273, [RS_MCS_6] = 307, [RS_MCS_7] = 341,
[RS_MCS_8] = 409, [RS_MCS_9] = 455, [RS_MCS_10] = 511, [RS_MCS_11] = 568,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 68, [RS_MCS_1] = 136, [RS_MCS_2] = 204, [RS_MCS_3] = 273,
[RS_MCS_4] = 409, [RS_MCS_5] = 546, [RS_MCS_6] = 614, [RS_MCS_7] = 682,
[RS_MCS_8] = 819, [RS_MCS_9] = 910, [RS_MCS_10] = 1023, [RS_MCS_11] = 1137,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 36, [RS_MCS_1] = 72, [RS_MCS_2] = 108, [RS_MCS_3] = 144,
[RS_MCS_4] = 216, [RS_MCS_5] = 289, [RS_MCS_6] = 325, [RS_MCS_7] = 361,
[RS_MCS_8] = 433, [RS_MCS_9] = 481, [RS_MCS_10] = 541, [RS_MCS_11] = 602,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 72, [RS_MCS_1] = 144, [RS_MCS_2] = 216, [RS_MCS_3] = 289,
[RS_MCS_4] = 433, [RS_MCS_5] = 578, [RS_MCS_6] = 650, [RS_MCS_7] = 722,
[RS_MCS_8] = 867, [RS_MCS_9] = 963, [RS_MCS_10] = 1083, [RS_MCS_11] = 1204,
},
},
},
[CHANNEL_WIDTH40] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 61, [RS_MCS_1] = 122, [RS_MCS_2] = 184, [RS_MCS_3] = 245,
[RS_MCS_4] = 368, [RS_MCS_5] = 491, [RS_MCS_6] = 552, [RS_MCS_7] = 614,
[RS_MCS_8] = 737, [RS_MCS_9] = 819, [RS_MCS_10] = 921, [RS_MCS_11] = 1023,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 122, [RS_MCS_1] = 245, [RS_MCS_2] = 368, [RS_MCS_3] = 491,
[RS_MCS_4] = 737, [RS_MCS_5] = 982, [RS_MCS_6] = 1105, [RS_MCS_7] = 1228,
[RS_MCS_8] = 1474, [RS_MCS_9] = 1638, [RS_MCS_10] = 1842, [RS_MCS_11] = 2047,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 68, [RS_MCS_1] = 136, [RS_MCS_2] = 204, [RS_MCS_3] = 273,
[RS_MCS_4] = 409, [RS_MCS_5] = 546, [RS_MCS_6] = 614, [RS_MCS_7] = 682,
[RS_MCS_8] = 819, [RS_MCS_9] = 910, [RS_MCS_10] = 1023, [RS_MCS_11] = 1137,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 136, [RS_MCS_1] = 273, [RS_MCS_2] = 409, [RS_MCS_3] = 546,
[RS_MCS_4] = 819, [RS_MCS_5] = 1092, [RS_MCS_6] = 1228, [RS_MCS_7] = 1365,
[RS_MCS_8] = 1638, [RS_MCS_9] = 1820, [RS_MCS_10] = 2047, [RS_MCS_11] = 2275,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 72, [RS_MCS_1] = 144, [RS_MCS_2] = 216, [RS_MCS_3] = 289,
[RS_MCS_4] = 433, [RS_MCS_5] = 578, [RS_MCS_6] = 650, [RS_MCS_7] = 722,
[RS_MCS_8] = 867, [RS_MCS_9] = 963, [RS_MCS_10] = 1083, [RS_MCS_11] = 1204,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 144, [RS_MCS_1] = 289, [RS_MCS_2] = 433, [RS_MCS_3] = 578,
[RS_MCS_4] = 867, [RS_MCS_5] = 1156, [RS_MCS_6] = 1300, [RS_MCS_7] = 1445,
[RS_MCS_8] = 1734, [RS_MCS_9] = 1927, [RS_MCS_10] = 2167, [RS_MCS_11] = 2408,
},
},
},
[CHANNEL_WIDTH80] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 128, [RS_MCS_1] = 257, [RS_MCS_2] = 385, [RS_MCS_3] = 514,
[RS_MCS_4] = 771, [RS_MCS_5] = 1029, [RS_MCS_6] = 1157, [RS_MCS_7] = 1286,
[RS_MCS_8] = 1543, [RS_MCS_9] = 1715, [RS_MCS_10] = 1929, [RS_MCS_11] = 2143,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 257, [RS_MCS_1] = 514, [RS_MCS_2] = 771, [RS_MCS_3] = 1029,
[RS_MCS_4] = 1543, [RS_MCS_5] = 2058, [RS_MCS_6] = 2315, [RS_MCS_7] = 2572,
[RS_MCS_8] = 3087, [RS_MCS_9] = 3430, [RS_MCS_10] = 3858, [RS_MCS_11] = 4287,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 142, [RS_MCS_1] = 285, [RS_MCS_2] = 428, [RS_MCS_3] = 571,
[RS_MCS_4] = 857, [RS_MCS_5] = 1143, [RS_MCS_6] = 1286, [RS_MCS_7] = 1429,
[RS_MCS_8] = 1715, [RS_MCS_9] = 1905, [RS_MCS_10] = 2143, [RS_MCS_11] = 2381,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 285, [RS_MCS_1] = 571, [RS_MCS_2] = 857, [RS_MCS_3] = 1143,
[RS_MCS_4] = 1715, [RS_MCS_5] = 2286, [RS_MCS_6] = 2572, [RS_MCS_7] = 2858,
[RS_MCS_8] = 3430, [RS_MCS_9] = 3811, [RS_MCS_10] = 4287, [RS_MCS_11] = 4763,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 151, [RS_MCS_1] = 302, [RS_MCS_2] = 453, [RS_MCS_3] = 605,
[RS_MCS_4] = 907, [RS_MCS_5] = 1210, [RS_MCS_6] = 1361, [RS_MCS_7] = 1513,
[RS_MCS_8] = 1815, [RS_MCS_9] = 2017, [RS_MCS_10] = 2269, [RS_MCS_11] = 2522,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 302, [RS_MCS_1] = 605, [RS_MCS_2] = 907, [RS_MCS_3] = 1210,
[RS_MCS_4] = 1815, [RS_MCS_5] = 2421, [RS_MCS_6] = 2723, [RS_MCS_7] = 3026,
[RS_MCS_8] = 3631, [RS_MCS_9] = 4035, [RS_MCS_10] = 4539, [RS_MCS_11] = 5044,
},
},
},
[CHANNEL_WIDTH160] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 257, [RS_MCS_1] = 514, [RS_MCS_2] = 771, [RS_MCS_3] = 1029,
[RS_MCS_4] = 1543, [RS_MCS_5] = 2058, [RS_MCS_6] = 2315, [RS_MCS_7] = 2572,
[RS_MCS_8] = 3087, [RS_MCS_9] = 3430, [RS_MCS_10] = 3858, [RS_MCS_11] = 4287,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 514, [RS_MCS_1] = 1029, [RS_MCS_2] = 1543, [RS_MCS_3] = 2058,
[RS_MCS_4] = 3087, [RS_MCS_5] = 4116, [RS_MCS_6] = 4630, [RS_MCS_7] = 5145,
[RS_MCS_8] = 6174, [RS_MCS_9] = 6860, [RS_MCS_10] = 7717, [RS_MCS_11] = 8575,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 285, [RS_MCS_1] = 571, [RS_MCS_2] = 857, [RS_MCS_3] = 1143,
[RS_MCS_4] = 1715, [RS_MCS_5] = 2286, [RS_MCS_6] = 2572, [RS_MCS_7] = 2858,
[RS_MCS_8] = 3430, [RS_MCS_9] = 3811, [RS_MCS_10] = 4287, [RS_MCS_11] = 4763,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 571, [RS_MCS_1] = 1143, [RS_MCS_2] = 1715, [RS_MCS_3] = 2286,
[RS_MCS_4] = 3430, [RS_MCS_5] = 4573, [RS_MCS_6] = 5145, [RS_MCS_7] = 5716,
[RS_MCS_8] = 6860, [RS_MCS_9] = 7622, [RS_MCS_10] = 8575, [RS_MCS_11] = 9527,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 302, [RS_MCS_1] = 605, [RS_MCS_2] = 907, [RS_MCS_3] = 1210,
[RS_MCS_4] = 1815, [RS_MCS_5] = 2421, [RS_MCS_6] = 2723, [RS_MCS_7] = 3026,
[RS_MCS_8] = 3631, [RS_MCS_9] = 4035, [RS_MCS_10] = 4539, [RS_MCS_11] = 5044,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 605, [RS_MCS_1] = 1210, [RS_MCS_2] = 1815, [RS_MCS_3] = 2421,
[RS_MCS_4] = 3631, [RS_MCS_5] = 4842, [RS_MCS_6] = 5447, [RS_MCS_7] = 6052,
[RS_MCS_8] = 7263, [RS_MCS_9] = 8070, [RS_MCS_10] = 9079, [RS_MCS_11] = 10088,
},
},
},
},
[RS_MNG_AGG] = {
[CHANNEL_WIDTH20] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 62, [RS_MCS_1] = 124, [RS_MCS_2] = 186, [RS_MCS_3] = 248,
[RS_MCS_4] = 372, [RS_MCS_5] = 497, [RS_MCS_6] = 559, [RS_MCS_7] = 621,
[RS_MCS_8] = 745, [RS_MCS_9] = 828, [RS_MCS_10] = 932, [RS_MCS_11] = 1035,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 124, [RS_MCS_1] = 248, [RS_MCS_2] = 372, [RS_MCS_3] = 497,
[RS_MCS_4] = 745, [RS_MCS_5] = 994, [RS_MCS_6] = 1118, [RS_MCS_7] = 1243,
[RS_MCS_8] = 1491, [RS_MCS_9] = 1657, [RS_MCS_10] = 1864, [RS_MCS_11] = 2071,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 69, [RS_MCS_1] = 138, [RS_MCS_2] = 207, [RS_MCS_3] = 276,
[RS_MCS_4] = 414, [RS_MCS_5] = 552, [RS_MCS_6] = 621, [RS_MCS_7] = 690,
[RS_MCS_8] = 828, [RS_MCS_9] = 920, [RS_MCS_10] = 1035, [RS_MCS_11] = 1151,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 138, [RS_MCS_1] = 276, [RS_MCS_2] = 414, [RS_MCS_3] = 552,
[RS_MCS_4] = 828, [RS_MCS_5] = 1105, [RS_MCS_6] = 1243, [RS_MCS_7] = 1381,
[RS_MCS_8] = 1657, [RS_MCS_9] = 1841, [RS_MCS_10] = 2071, [RS_MCS_11] = 2302,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 73, [RS_MCS_1] = 146, [RS_MCS_2] = 219, [RS_MCS_3] = 292,
[RS_MCS_4] = 438, [RS_MCS_5] = 585, [RS_MCS_6] = 658, [RS_MCS_7] = 731,
[RS_MCS_8] = 877, [RS_MCS_9] = 975, [RS_MCS_10] = 1096, [RS_MCS_11] = 1218,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 146, [RS_MCS_1] = 292, [RS_MCS_2] = 438, [RS_MCS_3] = 585,
[RS_MCS_4] = 877, [RS_MCS_5] = 1170, [RS_MCS_6] = 1316, [RS_MCS_7] = 1462,
[RS_MCS_8] = 1755, [RS_MCS_9] = 1950, [RS_MCS_10] = 2193, [RS_MCS_11] = 2437,
},
},
},
[CHANNEL_WIDTH40] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 124, [RS_MCS_1] = 248, [RS_MCS_2] = 372, [RS_MCS_3] = 497,
[RS_MCS_4] = 745, [RS_MCS_5] = 994, [RS_MCS_6] = 1118, [RS_MCS_7] = 1243,
[RS_MCS_8] = 1491, [RS_MCS_9] = 1657, [RS_MCS_10] = 1864, [RS_MCS_11] = 2071,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 248, [RS_MCS_1] = 497, [RS_MCS_2] = 745, [RS_MCS_3] = 994,
[RS_MCS_4] = 1491, [RS_MCS_5] = 1989, [RS_MCS_6] = 2237, [RS_MCS_7] = 2486,
[RS_MCS_8] = 2983, [RS_MCS_9] = 3315, [RS_MCS_10] = 3729, [RS_MCS_11] = 4143,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 138, [RS_MCS_1] = 276, [RS_MCS_2] = 414, [RS_MCS_3] = 552,
[RS_MCS_4] = 828, [RS_MCS_5] = 1105, [RS_MCS_6] = 1243, [RS_MCS_7] = 1381,
[RS_MCS_8] = 1657, [RS_MCS_9] = 1841, [RS_MCS_10] = 2071, [RS_MCS_11] = 2302,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 276, [RS_MCS_1] = 552, [RS_MCS_2] = 828, [RS_MCS_3] = 1105,
[RS_MCS_4] = 1657, [RS_MCS_5] = 2210, [RS_MCS_6] = 2486, [RS_MCS_7] = 2762,
[RS_MCS_8] = 3315, [RS_MCS_9] = 3683, [RS_MCS_10] = 4143, [RS_MCS_11] = 4604,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 146, [RS_MCS_1] = 292, [RS_MCS_2] = 438, [RS_MCS_3] = 585,
[RS_MCS_4] = 877, [RS_MCS_5] = 1170, [RS_MCS_6] = 1316, [RS_MCS_7] = 1462,
[RS_MCS_8] = 1755, [RS_MCS_9] = 1950, [RS_MCS_10] = 2193, [RS_MCS_11] = 2437,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 292, [RS_MCS_1] = 585, [RS_MCS_2] = 877, [RS_MCS_3] = 1170,
[RS_MCS_4] = 1755, [RS_MCS_5] = 2340, [RS_MCS_6] = 2632, [RS_MCS_7] = 2925,
[RS_MCS_8] = 3510, [RS_MCS_9] = 3900, [RS_MCS_10] = 4387, [RS_MCS_11] = 4875,
},
},
},
[CHANNEL_WIDTH80] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 260, [RS_MCS_1] = 520, [RS_MCS_2] = 780, [RS_MCS_3] = 1041,
[RS_MCS_4] = 1561, [RS_MCS_5] = 2082, [RS_MCS_6] = 2342, [RS_MCS_7] = 2603,
[RS_MCS_8] = 3123, [RS_MCS_9] = 3470, [RS_MCS_10] = 3904, [RS_MCS_11] = 4338,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 520, [RS_MCS_1] = 1041, [RS_MCS_2] = 1561, [RS_MCS_3] = 2082,
[RS_MCS_4] = 3123, [RS_MCS_5] = 4165, [RS_MCS_6] = 4685, [RS_MCS_7] = 5206,
[RS_MCS_8] = 6247, [RS_MCS_9] = 6941, [RS_MCS_10] = 7809, [RS_MCS_11] = 8677,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 289, [RS_MCS_1] = 578, [RS_MCS_2] = 867, [RS_MCS_3] = 1156,
[RS_MCS_4] = 1735, [RS_MCS_5] = 2313, [RS_MCS_6] = 2603, [RS_MCS_7] = 2892,
[RS_MCS_8] = 3470, [RS_MCS_9] = 3856, [RS_MCS_10] = 4338, [RS_MCS_11] = 4820,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 578, [RS_MCS_1] = 1156, [RS_MCS_2] = 1735, [RS_MCS_3] = 2313,
[RS_MCS_4] = 3470, [RS_MCS_5] = 4627, [RS_MCS_6] = 5206, [RS_MCS_7] = 5784,
[RS_MCS_8] = 6941, [RS_MCS_9] = 7712, [RS_MCS_10] = 8677, [RS_MCS_11] = 9641,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 306, [RS_MCS_1] = 612, [RS_MCS_2] = 918, [RS_MCS_3] = 1225,
[RS_MCS_4] = 1837, [RS_MCS_5] = 2450, [RS_MCS_6] = 2756, [RS_MCS_7] = 3062,
[RS_MCS_8] = 3675, [RS_MCS_9] = 4083, [RS_MCS_10] = 4593, [RS_MCS_11] = 5104,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 612, [RS_MCS_1] = 1225, [RS_MCS_2] = 1837, [RS_MCS_3] = 2450,
[RS_MCS_4] = 3675, [RS_MCS_5] = 4900, [RS_MCS_6] = 5512, [RS_MCS_7] = 6125,
[RS_MCS_8] = 7350, [RS_MCS_9] = 8166, [RS_MCS_10] = 9187, [RS_MCS_11] = 10208,
},
},
},
[CHANNEL_WIDTH160] = {
[RS_MNG_GI_3_2] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 520, [RS_MCS_1] = 1041, [RS_MCS_2] = 1561, [RS_MCS_3] = 2082,
[RS_MCS_4] = 3123, [RS_MCS_5] = 4165, [RS_MCS_6] = 4685, [RS_MCS_7] = 5206,
[RS_MCS_8] = 6247, [RS_MCS_9] = 6941, [RS_MCS_10] = 7809, [RS_MCS_11] = 8677,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 1041, [RS_MCS_1] = 2082, [RS_MCS_2] = 3123, [RS_MCS_3] = 4165,
[RS_MCS_4] = 6247, [RS_MCS_5] = 8330, [RS_MCS_6] = 9371, [RS_MCS_7] = 10412,
[RS_MCS_8] = 12495, [RS_MCS_9] = 13883, [RS_MCS_10] = 15618, [RS_MCS_11] = 17354,
},
},
[RS_MNG_GI_1_6] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 578, [RS_MCS_1] = 1156, [RS_MCS_2] = 1735, [RS_MCS_3] = 2313,
[RS_MCS_4] = 3470, [RS_MCS_5] = 4627, [RS_MCS_6] = 5206, [RS_MCS_7] = 5784,
[RS_MCS_8] = 6941, [RS_MCS_9] = 7712, [RS_MCS_10] = 8677, [RS_MCS_11] = 9641,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 1156, [RS_MCS_1] = 2313, [RS_MCS_2] = 3470, [RS_MCS_3] = 4627,
[RS_MCS_4] = 6941, [RS_MCS_5] = 9255, [RS_MCS_6] = 10412, [RS_MCS_7] = 11569,
[RS_MCS_8] = 13883, [RS_MCS_9] = 15425, [RS_MCS_10] = 17354, [RS_MCS_11] = 19282,
},
},
[RS_MNG_GI_0_8] = {
[RS_MNG_SISO] = {
[RS_MCS_0] = 612, [RS_MCS_1] = 1225, [RS_MCS_2] = 1837, [RS_MCS_3] = 2450,
[RS_MCS_4] = 3675, [RS_MCS_5] = 4900, [RS_MCS_6] = 5512, [RS_MCS_7] = 6125,
[RS_MCS_8] = 7350, [RS_MCS_9] = 8166, [RS_MCS_10] = 9187, [RS_MCS_11] = 10208,
},
[RS_MNG_MIMO] = {
[RS_MCS_0] = 1225, [RS_MCS_1] = 2450, [RS_MCS_2] = 3675, [RS_MCS_3] = 4900,
[RS_MCS_4] = 7350, [RS_MCS_5] = 9800, [RS_MCS_6] = 11025, [RS_MCS_7] = 12250,
[RS_MCS_8] = 14700, [RS_MCS_9] = 16333, [RS_MCS_10] = 18375, [RS_MCS_11] = 20416,
},
},
},
},
};
/*******************************************************************************/
/************************************************************************************/
/************************ Aggergation ********************************/
/************************************************************************************/
// Default values for Aggregation Params
// info about the relevant fields can be found for LINK_QUAL_AGG_PARAMS_API_S
#define RS_MNG_AGG_DISABLE_START_TH 3
/*******************************************************************************/
static const RS_MNG_STA_LIMITS_S g_rsMngStaModLimits[] = {
{
// HT/VHT/HE
.successFramesLimit = RS_MNG_NON_LEGACY_SUCCESS_LIMIT,
.failedFramesLimit = RS_MNG_NON_LEGACY_FAILURE_LIMIT,
.statsFlushTimeLimit = RS_MNG_STATS_FLUSH_TIME_LIMIT,
.clearTblWindowsLimit = RS_MNG_NON_LEGACY_MOD_COUNTER_LIMIT,
},
{
// non-HT
.successFramesLimit = RS_MNG_LEGACY_SUCCESS_LIMIT,
.failedFramesLimit = RS_MNG_LEGACY_FAILURE_LIMIT,
.statsFlushTimeLimit = RS_MNG_STATS_FLUSH_TIME_LIMIT,
.clearTblWindowsLimit = RS_MNG_LEGACY_MOD_COUNTER_LIMIT,
}};
static BOOLEAN _allowColAnt(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static BOOLEAN _allowColMimo(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static BOOLEAN _allowColSiso(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static BOOLEAN _allowColSgi(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static BOOLEAN _alloCol2xLTF(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static BOOLEAN _allowColHe(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static BOOLEAN _allowColHtVht(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol);
static const RS_MNG_COL_ELEM_S rsMngColumns[] = {
[RS_MNG_COL_NON_HT_ANT_A] =
{
.mode = RS_MNG_MODUL_LEGACY,
.ant = TLC_MNG_CHAIN_A_MSK,
.nextCols = {RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_SISO_ANT_A, RS_MNG_COL_MIMO2,
RS_MNG_COL_HE_3_2_SISO_ANT_A, RS_MNG_COL_HE_3_2_MIMO, RS_MNG_COL_INVALID,
RS_MNG_COL_INVALID},
.checks = {_allowColAnt},
},
[RS_MNG_COL_NON_HT_ANT_B] =
{
.mode = RS_MNG_MODUL_LEGACY,
.ant = TLC_MNG_CHAIN_B_MSK,
.nextCols = {RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_SISO_ANT_B, RS_MNG_COL_MIMO2,
RS_MNG_COL_HE_3_2_SISO_ANT_B, RS_MNG_COL_HE_3_2_MIMO, RS_MNG_COL_INVALID,
RS_MNG_COL_INVALID},
.checks = {_allowColAnt},
},
[RS_MNG_COL_SISO_ANT_A] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_A_MSK,
.nextCols = {RS_MNG_COL_SISO_ANT_B, RS_MNG_COL_MIMO2, RS_MNG_COL_SISO_ANT_A_SGI,
RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID,
RS_MNG_COL_INVALID},
.checks = {_allowColHtVht, _allowColSiso, _allowColAnt},
},
[RS_MNG_COL_SISO_ANT_B] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_B_MSK,
.nextCols = {RS_MNG_COL_SISO_ANT_A, RS_MNG_COL_MIMO2, RS_MNG_COL_SISO_ANT_B_SGI,
RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID,
RS_MNG_COL_INVALID},
.checks = {_allowColHtVht, _allowColSiso, _allowColAnt},
},
[RS_MNG_COL_SISO_ANT_A_SGI] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_A_MSK,
.gi = HT_VHT_SGI,
.nextCols = {RS_MNG_COL_SISO_ANT_B_SGI, RS_MNG_COL_MIMO2_SGI, RS_MNG_COL_SISO_ANT_A,
RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID,
RS_MNG_COL_INVALID},
.checks = {_allowColHtVht, _allowColSiso, _allowColAnt, _allowColSgi},
},
[RS_MNG_COL_SISO_ANT_B_SGI] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_B_MSK,
.gi = HT_VHT_SGI,
.nextCols = {RS_MNG_COL_SISO_ANT_A_SGI, RS_MNG_COL_MIMO2_SGI, RS_MNG_COL_SISO_ANT_B,
RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID,
RS_MNG_COL_INVALID},
.checks = {_allowColHtVht, _allowColSiso, _allowColAnt, _allowColSgi},
},
[RS_MNG_COL_MIMO2] =
{
.mode = RS_MNG_MODUL_MIMO2,
.ant = TLC_MNG_CHAIN_A_MSK | TLC_MNG_CHAIN_B_MSK,
.nextCols =
{RS_MNG_COL_SISO_ANT_A, // + NON_SHARED_ANT_RFIC_ID (see _rsMngGetNextColId)
RS_MNG_COL_MIMO2_SGI, RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B,
RS_MNG_COL_INVALID, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHtVht, _allowColMimo},
},
[RS_MNG_COL_MIMO2_SGI] =
{
.mode = RS_MNG_MODUL_MIMO2,
.ant = TLC_MNG_CHAIN_A_MSK | TLC_MNG_CHAIN_B_MSK,
.gi = HT_VHT_SGI,
.nextCols =
{RS_MNG_COL_SISO_ANT_A_SGI, // + NON_SHARED_ANT_RFIC_ID (see _rsMngGetNextColId)
RS_MNG_COL_MIMO2, RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B,
RS_MNG_COL_INVALID, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHtVht, _allowColMimo, _allowColSgi},
},
[RS_MNG_COL_HE_3_2_SISO_ANT_A] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_A_MSK,
.gi = HE_3_2_GI,
.nextCols = {RS_MNG_COL_HE_3_2_SISO_ANT_B, RS_MNG_COL_HE_3_2_MIMO,
RS_MNG_COL_HE_1_6_SISO_ANT_A, RS_MNG_COL_NON_HT_ANT_A,
RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColSiso, _allowColAnt},
},
[RS_MNG_COL_HE_1_6_SISO_ANT_A] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_A_MSK,
.gi = HE_1_6_GI,
.nextCols = {RS_MNG_COL_HE_1_6_SISO_ANT_B, RS_MNG_COL_HE_1_6_MIMO,
RS_MNG_COL_HE_0_8_SISO_ANT_A, RS_MNG_COL_HE_3_2_SISO_ANT_A,
RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColSiso, _allowColAnt, _alloCol2xLTF},
},
[RS_MNG_COL_HE_0_8_SISO_ANT_A] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_A_MSK,
.gi = HE_0_8_GI,
.nextCols = {RS_MNG_COL_HE_0_8_SISO_ANT_B, RS_MNG_COL_HE_0_8_MIMO,
RS_MNG_COL_HE_1_6_SISO_ANT_A, RS_MNG_COL_NON_HT_ANT_A,
RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColSiso, _allowColAnt, _alloCol2xLTF},
},
[RS_MNG_COL_HE_3_2_SISO_ANT_B] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_B_MSK,
.gi = HE_3_2_GI,
.nextCols = {RS_MNG_COL_HE_3_2_SISO_ANT_A, RS_MNG_COL_HE_3_2_MIMO,
RS_MNG_COL_HE_1_6_SISO_ANT_B, RS_MNG_COL_NON_HT_ANT_A,
RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColSiso, _allowColAnt},
},
[RS_MNG_COL_HE_1_6_SISO_ANT_B] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_B_MSK,
.gi = HE_1_6_GI,
.nextCols = {RS_MNG_COL_HE_1_6_SISO_ANT_A, RS_MNG_COL_HE_1_6_MIMO,
RS_MNG_COL_HE_0_8_SISO_ANT_B, RS_MNG_COL_HE_3_2_SISO_ANT_B,
RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColSiso, _allowColAnt, _alloCol2xLTF},
},
[RS_MNG_COL_HE_0_8_SISO_ANT_B] =
{
.mode = RS_MNG_MODUL_SISO,
.ant = TLC_MNG_CHAIN_B_MSK,
.gi = HE_0_8_GI,
.nextCols = {RS_MNG_COL_HE_0_8_SISO_ANT_A, RS_MNG_COL_HE_0_8_MIMO,
RS_MNG_COL_HE_1_6_SISO_ANT_B, RS_MNG_COL_NON_HT_ANT_A,
RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColSiso, _allowColAnt, _alloCol2xLTF},
},
[RS_MNG_COL_HE_3_2_MIMO] =
{
.mode = RS_MNG_MODUL_MIMO2,
.ant = TLC_MNG_CHAIN_A_MSK | TLC_MNG_CHAIN_B_MSK,
.gi = HE_3_2_GI,
.nextCols =
{RS_MNG_COL_HE_3_2_SISO_ANT_A, // + NON_SHARED_ANT_RFIC_ID (see _rsMngGetNextColId)
RS_MNG_COL_HE_1_6_MIMO, RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B,
RS_MNG_COL_INVALID, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColMimo},
},
[RS_MNG_COL_HE_1_6_MIMO] =
{
.mode = RS_MNG_MODUL_MIMO2,
.ant = TLC_MNG_CHAIN_A_MSK | TLC_MNG_CHAIN_B_MSK,
.gi = HE_1_6_GI,
.nextCols =
{RS_MNG_COL_HE_1_6_SISO_ANT_A, // + NON_SHARED_ANT_RFIC_ID (see _rsMngGetNextColId)
RS_MNG_COL_HE_0_8_MIMO, RS_MNG_COL_HE_3_2_MIMO, RS_MNG_COL_NON_HT_ANT_A,
RS_MNG_COL_NON_HT_ANT_B, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColMimo, _alloCol2xLTF},
},
[RS_MNG_COL_HE_0_8_MIMO] =
{
.mode = RS_MNG_MODUL_MIMO2,
.ant = TLC_MNG_CHAIN_A_MSK | TLC_MNG_CHAIN_B_MSK,
.gi = HE_0_8_GI,
.nextCols =
{RS_MNG_COL_HE_0_8_SISO_ANT_A, // + NON_SHARED_ANT_RFIC_ID (see _rsMngGetNextColId)
RS_MNG_COL_HE_1_6_MIMO, RS_MNG_COL_NON_HT_ANT_A, RS_MNG_COL_NON_HT_ANT_B,
RS_MNG_COL_INVALID, RS_MNG_COL_INVALID, RS_MNG_COL_INVALID},
.checks = {_allowColHe, _allowColMimo, _alloCol2xLTF},
},
};
/*******************************************************************************/
/*******************************************************************************/
/* General Helper functions */
/*******************************************************************************/
static void _rsMngRateCheckSet(const RS_MNG_RATE_S* rsMngRate,
RS_MNG_RATE_SETTING_BITMAP_E setting) {
WARN_ON(rsMngRate->unset & setting);
}
static RS_MNG_MODULATION_E _rsMngRateGetModulation(const RS_MNG_RATE_S* rsMngRate) {
RS_MNG_MODULATION_E modulation;
if (IS_RATE_OFDM_VHT_API_M(rsMngRate->rate) || IS_RATE_OFDM_HT_API_M(rsMngRate->rate) ||
IS_RATE_OFDM_HE_API_M(rsMngRate->rate)) {
if (GET_MIMO_INDEX_API_M(rsMngRate->rate) == SISO_INDX) {
modulation = RS_MNG_MODUL_SISO;
} else {
modulation = RS_MNG_MODUL_MIMO2;
}
} else {
modulation = RS_MNG_MODUL_LEGACY;
}
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_MODULATION);
return modulation;
}
static void _rsMngRateSetModulation(RS_MNG_RATE_S* rsMngRate, RS_MNG_MODULATION_E mod) {
if (mod == RS_MNG_MODUL_MIMO2) {
if (IS_RATE_OFDM_VHT_API_M(rsMngRate->rate) || IS_RATE_OFDM_HE_API_M(rsMngRate->rate)) {
rsMngRate->rate.rate_n_flags |= RATE_MCS_VHT_MIMO2;
} else {
rsMngRate->rate.rate_n_flags |= RATE_MCS_HT_MIMO2_MSK;
}
}
if (mod == RS_MNG_MODUL_SISO) {
if (IS_RATE_OFDM_VHT_API_M(rsMngRate->rate) || IS_RATE_OFDM_HE_API_M(rsMngRate->rate)) {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_VHT_MIMO2;
} else {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_HT_MIMO2_MSK;
}
}
rsMngRate->unset &= ~RS_MNG_RATE_MODULATION;
rsMngRate->unset |= RS_MNG_RATE_STBC;
}
static TLC_MNG_MODE_E _rsMngRateGetMode(const RS_MNG_RATE_S* rsMngRate) {
TLC_MNG_MODE_E rateMode;
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_MODE);
if (IS_RATE_OFDM_HE_API_M(rsMngRate->rate)) {
rateMode = TLC_MNG_MODE_HE;
} else if (IS_RATE_OFDM_VHT_API_M(rsMngRate->rate)) {
rateMode = TLC_MNG_MODE_VHT;
} else if (IS_RATE_OFDM_HT_API_M(rsMngRate->rate)) {
rateMode = TLC_MNG_MODE_HT;
} else {
rateMode = TLC_MNG_MODE_LEGACY;
}
return rateMode;
}
static void _rsMngRateSetMode(RS_MNG_RATE_S* rsMngRate, TLC_MNG_MODE_E mode) {
/* This resets the rate completely */
rsMngRate->rate.rate_n_flags = 0;
/* We don't really use bfer, so don't mark it as reset */
rsMngRate->unset = RS_MNG_RATE_SET_ALL & ~(RS_MNG_RATE_MODE | RS_MNG_RATE_BFER);
switch (mode) {
case TLC_MNG_MODE_LEGACY:
break;
case TLC_MNG_MODE_HT:
rsMngRate->rate.rate_n_flags |= RATE_MCS_HT_MSK;
break;
case TLC_MNG_MODE_VHT:
rsMngRate->rate.rate_n_flags |= RATE_MCS_VHT_MSK;
break;
case TLC_MNG_MODE_HE:
rsMngRate->rate.rate_n_flags |= RATE_MCS_HE_MSK;
break;
default:
break;
}
}
static U32 _rsMngRateGetBw(const RS_MNG_RATE_S* rsMngRate) {
U32 bw = GET_BW_INDEX_API_M(rsMngRate->rate);
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_BW);
return bw;
}
static void _rsMngRateSetBw(RS_MNG_RATE_S* rsMngRate, U32 bw) {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_FAT_MSK_API_D;
rsMngRate->rate.rate_n_flags |= bw << RATE_MCS_FAT_POS;
rsMngRate->unset &= ~RS_MNG_RATE_BW;
}
static RS_MNG_GI_E _rsMngRateGetGi(const RS_MNG_RATE_S* rsMngRate) {
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_GI);
if (_rsMngRateGetMode(rsMngRate) != TLC_MNG_MODE_HE) {
return (rsMngRate->rate.rate_n_flags & RATE_MCS_SGI_MSK) ? HT_VHT_SGI : HT_VHT_NGI;
}
switch (GET_OFDM_HE_GI_LTF_INDX_API_M(rsMngRate->rate)) {
case 0:
case 1:
return HE_0_8_GI;
case 2:
return HE_1_6_GI;
case 3:
return HE_3_2_GI;
}
return HT_VHT_NGI; // impossible
}
static void _rsMngRateSetGi(RS_MNG_RATE_S* rsMngRate, RS_MNG_GI_E gi) {
if (_rsMngRateGetMode(rsMngRate) != TLC_MNG_MODE_HE) {
WARN_ON(!(gi == HT_VHT_NGI || gi == HT_VHT_SGI));
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_SGI_MSK;
rsMngRate->rate.rate_n_flags |= (gi == HT_VHT_SGI) << RATE_MCS_SGI_POS;
} else {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_HE_GI_LTF_MSK;
switch (gi) {
case HT_VHT_NGI:
case HT_VHT_SGI:
WARN_ON(1);
break;
case HE_0_8_GI:
// 2xLTF
rsMngRate->rate.rate_n_flags |= 1 << RATE_MCS_HE_GI_LTF_POS;
break;
case HE_1_6_GI:
// 2xLTF
rsMngRate->rate.rate_n_flags |= 2 << RATE_MCS_HE_GI_LTF_POS;
break;
case HE_3_2_GI:
// 4xLTF
rsMngRate->rate.rate_n_flags |= 3 << RATE_MCS_HE_GI_LTF_POS;
break;
}
}
rsMngRate->unset &= ~RS_MNG_RATE_GI;
}
static void _rsMngRateSetLdpc(RS_MNG_RATE_S* rsMngRate, BOOLEAN ldpc) {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_LDPC_MSK;
rsMngRate->rate.rate_n_flags |= (!!ldpc) << RATE_MCS_LDPC_POS;
rsMngRate->unset &= ~RS_MNG_RATE_LDPC;
}
static BOOLEAN _rsMngRateGetStbc(const RS_MNG_RATE_S* rsMngRate) {
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_STBC);
return !!(rsMngRate->rate.rate_n_flags & RATE_MCS_STBC_MSK);
}
static void _rsMngRateSetStbc(RS_MNG_RATE_S* rsMngRate, BOOLEAN stbc) {
WARN_ON(!(!stbc || !(rsMngRate->rate.rate_n_flags & RATE_MCS_HE_DCM_MSK)));
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_STBC_MSK;
rsMngRate->rate.rate_n_flags |= (!!stbc) << RATE_MCS_STBC_POS;
rsMngRate->unset &= ~RS_MNG_RATE_STBC;
rsMngRate->unset |= RS_MNG_RATE_ANT;
}
static void _rsMngRateSetBfer(RS_MNG_RATE_S* rsMngRate, BOOLEAN bfer) {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_BF_MSK;
rsMngRate->rate.rate_n_flags |= (!!bfer) << RATE_MCS_BF_POS;
rsMngRate->unset &= ~RS_MNG_RATE_BFER;
}
static U08 _rsMngRateGetAnt(const RS_MNG_RATE_S* rsMngRate) {
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_ANT);
return (U08)GET_ANT_CHAIN_API_M(rsMngRate->rate);
;
}
static void _rsMngRateSetAnt(RS_MNG_RATE_S* rsMngRate, U08 ant) {
// compilation asserts to make sure tlc offload api and rate api agree
BUILD_BUG_ON(!(TLC_MNG_CHAIN_A_MSK ==
SHIFT_AND_MASK(RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_ABC_MSK, RATE_MCS_ANT_A_POS)));
BUILD_BUG_ON(!(TLC_MNG_CHAIN_B_MSK ==
SHIFT_AND_MASK(RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_ABC_MSK, RATE_MCS_ANT_A_POS)));
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
rsMngRate->rate.rate_n_flags |= ant << RATE_MCS_ANT_A_POS;
rsMngRate->unset &= ~RS_MNG_RATE_ANT;
}
static U08 _rsMngRateGetIdx(const RS_MNG_RATE_S* rsMngRate) { return rsMngRate->idx.idx; }
static void _rsMngRateSetIdx(RS_MNG_RATE_S* rsMngRate, U08 idx) {
rsMngRate->idx.idx = idx;
// DCM and STBC can't coexist. Since DCM is set here, make sure stbc has been set before setting
// the index, so the stbc setting could be overriden here without issue
_rsMngRateCheckSet(rsMngRate, RS_MNG_RATE_STBC);
switch (_rsMngRateGetMode(rsMngRate)) {
case TLC_MNG_MODE_HE:
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_VHT_RATE_CODE_MSK;
if (idx == RS_MCS_0_HE_ER_AND_DCM) {
rsMngRate->rate.rate_n_flags |=
RATE_MCS_HE_DCM_MSK | (RATE_MCS_HE_EXT_RANGE << RATE_MCS_VHT_HE_TYPE_POS);
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_STBC_MSK;
} else {
rsMngRate->rate.rate_n_flags &= ~(RATE_MCS_HE_DCM_MSK | RATE_MCS_VHT_HE_TYPE_MSK);
rsMngRate->rate.rate_n_flags |= idx;
}
break;
case TLC_MNG_MODE_VHT:
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_VHT_RATE_CODE_MSK;
rsMngRate->rate.rate_n_flags |= idx;
break;
case TLC_MNG_MODE_HT:
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_HT_RATE_CODE_MSK;
rsMngRate->rate.rate_n_flags |= idx;
break;
case TLC_MNG_MODE_LEGACY: {
RS_NON_HT_RATES_E nonHtIdx = (RS_NON_HT_RATES_E)idx;
rsMngRate->rate.rate_n_flags &= ~0xff;
rsMngRate->rate.rate_n_flags |= RS_NON_HT_RATE_TO_API_RATE[nonHtIdx];
if (nonHtIdx <= RS_NON_HT_RATE_CCK_LAST) {
rsMngRate->rate.rate_n_flags |= RATE_MCS_CCK_MSK;
} else {
rsMngRate->rate.rate_n_flags &= ~RATE_MCS_CCK_MSK;
}
break;
}
default:
// shouldn't happen. return now so the index remains unset and an assert will be hit when
// trying to build the rate table with this rate
return;
}
rsMngRate->unset &= ~RS_MNG_RATE_U_IDX;
}
static void _rsMngRateInvalidate(RS_MNG_RATE_S* rsMngRate) {
rsMngRate->unset = RS_MNG_RATE_SET_ALL;
}
static U16 _rsMngGetSupportedRatesByModeAndBw(const RS_MNG_STA_INFO_S* staInfo,
RS_MNG_MODULATION_E modulation,
TLC_MNG_CH_WIDTH_E bw) {
BOOLEAN isBw160;
U32 supportedRates;
if (modulation == RS_MNG_MODUL_LEGACY) {
return staInfo->config.nonHt;
}
isBw160 = (bw == TLC_MNG_CH_WIDTH_160MHZ);
supportedRates = (modulation == RS_MNG_MODUL_SISO ? staInfo->config.mcs[TLC_MNG_NSS_1][isBw160]
: staInfo->config.mcs[TLC_MNG_NSS_2][isBw160]);
if (staInfo->config.bestSuppMode == TLC_MNG_MODE_VHT && bw == CHANNEL_WIDTH20) {
// In VHT, mcs 9 is never posible at 20mhz bandwidth
supportedRates &= ~BIT(RS_MCS_9);
}
return (U16)supportedRates;
}
static U16 _rsMngGetSuppRatesSameMode(const RS_MNG_STA_INFO_S* staInfo,
const RS_MNG_RATE_S* rsMngRate) {
return _rsMngGetSupportedRatesByModeAndBw(staInfo, _rsMngRateGetModulation(rsMngRate),
_rsMngRateGetBw(rsMngRate));
}
static TLC_MNG_CH_WIDTH_E _rsMngGetMaxChWidth(const RS_MNG_STA_INFO_S* staInfo) {
return (TLC_MNG_CH_WIDTH_E)staInfo->config.maxChWidth;
}
static BOOLEAN _rsMngAreAggsSupported(TLC_MNG_MODE_E bestSuppMode) {
return bestSuppMode > TLC_MNG_MODE_LEGACY;
}
static BOOLEAN _rsMngIsDcmSupported(const RS_MNG_STA_INFO_S* staInfo, BOOLEAN isMimo) {
if (isMimo) {
return !!(staInfo->config.configFlags & TLC_MNG_CONFIG_FLAGS_HE_DCM_NSS_2_MSK);
}
return !!(staInfo->config.configFlags & TLC_MNG_CONFIG_FLAGS_HE_DCM_NSS_1_MSK);
}
static BOOLEAN _rsMngRateIsOptimal(const RS_MNG_STA_INFO_S* staInfo,
const RS_MNG_RATE_S* rsMngRate) {
U32 bw = _rsMngRateGetBw(rsMngRate);
BOOLEAN mimoAllowed = staInfo->config.mcs[TLC_MNG_NSS_2][bw == CHANNEL_WIDTH160];
if (_rsMngRateGetMode(rsMngRate) != staInfo->config.bestSuppMode) {
return FALSE;
}
if (_rsMngRateGetIdx(rsMngRate) != MSB2ORD(_rsMngGetSuppRatesSameMode(staInfo, rsMngRate))) {
return FALSE;
}
// TODO: check for best ltf/gi in HE. This condition currently means that tpc won't be enabled
// in HE.
if ((staInfo->config.sgiChWidthSupport & BIT(bw)) && _rsMngRateGetGi(rsMngRate) != HT_VHT_SGI) {
return FALSE;
}
if (mimoAllowed && _rsMngRateGetModulation(rsMngRate) != RS_MNG_MODUL_MIMO2) {
return FALSE;
}
if (bw != _rsMngGetMaxChWidth(staInfo)) {
return FALSE;
}
return TRUE;
}
static U08 _rsMngGetHigherRateIdx(U08 initRateIdx, U32 supportedRatesMsk) {
U32 tmpRateMsk;
if (initRateIdx == RS_MCS_0_HE_ER_AND_DCM) {
return (U08)LSB2ORD(supportedRatesMsk);
}
tmpRateMsk = supportedRatesMsk & (0xFFFFFFFF << (initRateIdx + 1));
return (U08)(tmpRateMsk == 0 ? RS_MNG_INVALID_RATE_IDX : LSB2ORD(tmpRateMsk));
}
static U08 _rsMngGetLowerRateIdx(const RS_MNG_STA_INFO_S* staInfo, const RS_MNG_RATE_S* rate,
U32 supportedRatesMsk) {
U08 idx = _rsMngRateGetIdx(rate);
U32 tmpRateMsk = (supportedRatesMsk & ((1 << idx) - 1));
if (idx == RS_MCS_0_HE_ER_AND_DCM) {
return RS_MNG_INVALID_RATE_IDX;
}
if (tmpRateMsk == 0) {
if (_rsMngRateGetMode(rate) == TLC_MNG_MODE_HE && _rsMngRateGetBw(rate) == CHANNEL_WIDTH20 &&
_rsMngIsDcmSupported(staInfo, _rsMngRateGetModulation(rate) == RS_MNG_MODUL_MIMO2)) {
return RS_MCS_0_HE_ER_AND_DCM;
}
return RS_MNG_INVALID_RATE_IDX;
}
return (U08)MSB2ORD(tmpRateMsk);
}
// rs_get_adjacent_rate
// get adjacent supported rate
// suppRateDir : use GET_HIGHER_SUPPORTED_RATE or GET_LOWER_SUPPORTED_RATE
static U08 _rsMngGetAdjacentRateIdx(const RS_MNG_STA_INFO_S* staInfo, const RS_MNG_RATE_S* initRate,
U08 suppRateDir) {
U08 initRateIdx = _rsMngRateGetIdx(initRate);
U32 supportedRatesMsk = _rsMngGetSuppRatesSameMode(staInfo, initRate);
return (U08)(suppRateDir == GET_LOWER_SUPPORTED_RATE
? _rsMngGetLowerRateIdx(staInfo, initRate, supportedRatesMsk)
: _rsMngGetHigherRateIdx(initRateIdx, supportedRatesMsk));
}
// TODO - check. what if bt doesn't allow?
static BOOLEAN _rsMngIsStbcSupported(const RS_MNG_STA_INFO_S* staInfo) {
return !!(staInfo->config.configFlags & TLC_MNG_CONFIG_FLAGS_STBC_MSK);
}
static BOOLEAN _rsMngIsStbcAllowed(const RS_MNG_STA_INFO_S* staInfo, const RS_MNG_RATE_S* rate) {
if ((iwl_mvm_get_valid_tx_ant(staInfo->mvm) & rsMngGetDualAntMsk()) != rsMngGetDualAntMsk()) {
return FALSE;
}
return _rsMngIsStbcSupported(staInfo) && !(rate->rate.rate_n_flags & RATE_MCS_HE_DCM_MSK);
}
static BOOLEAN _rsMngCoexIsLongAggAllowed(const RS_MNG_STA_INFO_S* staInfo) {
if (staInfo->config.band != NL80211_BAND_2GHZ) {
return TRUE;
}
if (btCoexManagerBtOwnsAnt(staInfo->mvm)) {
return FALSE;
}
return TRUE;
}
static BOOLEAN _rsMngIsLdpcAllowed(const RS_MNG_STA_INFO_S* staInfo) {
return !!(staInfo->config.configFlags & TLC_MNG_CONFIG_FLAGS_LDPC_MSK);
}
static BOOLEAN _rsMngIsAntSupported(const RS_MNG_STA_INFO_S* staInfo, U08 ant) {
return (ant & staInfo->config.chainsEnabled) == ant &&
(iwl_mvm_get_valid_tx_ant(staInfo->mvm) & ant) == ant;
}
/*******************************************************************************/
/************************************************************************************/
/* allowColFuncs */
/************************************************************************************/
static BOOLEAN _allowColAnt(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
if (!_rsMngIsAntSupported(staInfo, nextCol->ant)) {
return FALSE;
}
if (!_rsMngIsAntSupported(staInfo, (U08)(nextCol->ant ^ rsMngGetDualAntMsk()))) {
// If the other antenna is disabled for some reason, this antenna is the only one allowed so
// we must ignore possible BT-Coex restrictions. Also note that this function is only called
// for siso columns, so nextCol->ant always has just one bit set so the xor makes sense.
return TRUE;
}
if (staInfo->config.band != NL80211_BAND_2GHZ) {
return TRUE;
}
if (btCoexManagerIsAntAvailable(staInfo->mvm, nextCol->ant)) {
return TRUE;
}
return FALSE;
}
static U16 _rsMngGetAggTimeLimit(RS_MNG_STA_INFO_S* staInfo) {
// Someone configured debug values, use them no matter what
if (staInfo->aggDurationLimit != RS_MNG_AGG_DURATION_LIMIT) {
return staInfo->aggDurationLimit;
}
if (_rsMngCoexIsLongAggAllowed(staInfo)) {
staInfo->longAggEnabled = TRUE;
return RS_MNG_AGG_DURATION_LIMIT;
}
staInfo->longAggEnabled = FALSE;
return RS_MNG_AGG_DURATION_LIMIT_SHORT;
}
static BOOLEAN _allowColMimo(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
BOOLEAN isBw160 = (bw == TLC_MNG_CH_WIDTH_160MHZ);
// TODO - check if ht/vht supported? redundent
// if no mimo rate is supported
if (!(staInfo->config.mcs[TLC_MNG_NSS_2][isBw160])) {
return FALSE;
}
if (staInfo->config.chainsEnabled != rsMngGetDualAntMsk()) {
return FALSE;
}
if (iwl_mvm_get_valid_tx_ant(staInfo->mvm) != rsMngGetDualAntMsk()) {
return FALSE;
}
return TRUE;
}
static BOOLEAN _allowColSiso(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
BOOLEAN isBw160 = (bw == TLC_MNG_CH_WIDTH_160MHZ);
// if there are supported SISO rates - return true. else - return false
return (!!(staInfo->config.mcs[TLC_MNG_NSS_1][isBw160]));
}
static BOOLEAN _allowColHe(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
return !!(staInfo->config.bestSuppMode == TLC_MNG_MODE_HE);
}
static BOOLEAN _allowColHtVht(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
return !!(staInfo->config.bestSuppMode == TLC_MNG_MODE_HT ||
staInfo->config.bestSuppMode == TLC_MNG_MODE_VHT);
}
static BOOLEAN _allowColSgi(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
U08 sgiChWidthSupport = staInfo->config.sgiChWidthSupport;
return !!(sgiChWidthSupport & BIT(bw));
}
static BOOLEAN _alloCol2xLTF(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
return !(staInfo->config.configFlags & TLC_MNG_CONFIG_FLAGS_HE_BLOCK_2X_LTF_MSK);
}
/***************************************************************/
static BOOLEAN _rsMngTpcIsActive(const RS_MNG_STA_INFO_S* staInfo) {
// There are 2 values for currStep that mean tpc isn't working currently - RS_MNG_TPC_INACTIVE
// and RS_MNG_TPC_DISABLED.
return staInfo->tpcTable.currStep < RS_MNG_TPC_NUM_STEPS;
}
static BOOLEAN _rsMngIsTestWindow(const RS_MNG_STA_INFO_S* staInfo) {
return staInfo->tryingRateUpscale || staInfo->searchBetterTbl || staInfo->tpcTable.testing;
}
static void _rsMngFillAggParamsLQCmd(RS_MNG_STA_INFO_S* staInfo, struct iwl_lq_cmd* lqCmd) {
lqCmd->agg_time_limit = cpu_to_le16(_rsMngGetAggTimeLimit(staInfo));
lqCmd->agg_disable_start_th = RS_MNG_AGG_DISABLE_START_TH;
// W/A for a HW bug that causes it to not prepare a second burst if the first one uses
// all frames in the Fifo. W/A this by making sure there's always at least one frame left.
lqCmd->agg_frame_cnt_limit = (U08)(staInfo->staBuffSize - 1);
}
// Get the next supported lower rate in the current column.
// return:
// the found rate index, or
// RS_MNG_INVALID_RATE_IDX if no such rate exists
static U08 _rsMngSetLowerRate(const RS_MNG_STA_INFO_S* staInfo, RS_MNG_RATE_S* rsMngRate) {
U08 lowerSuppRateIdx = _rsMngGetAdjacentRateIdx(staInfo, rsMngRate, GET_LOWER_SUPPORTED_RATE);
// if this is the lowest rate possible and this is not legacy rate - break;
if (RS_MNG_INVALID_RATE_IDX != lowerSuppRateIdx) {
_rsMngRateSetIdx(rsMngRate, lowerSuppRateIdx);
}
return lowerSuppRateIdx;
}
static void tlcMngNotifyAmsdu(const RS_MNG_STA_INFO_S* staInfo, U16 amsduSize, U16 tidBitmap) {
int i;
staInfo->mvmsta->amsdu_enabled = tidBitmap;
staInfo->mvmsta->max_amsdu_len = amsduSize;
staInfo->sta->max_rc_amsdu_len = staInfo->mvmsta->max_amsdu_len;
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
if (staInfo->mvmsta->amsdu_enabled & BIT(i))
staInfo->sta->max_tid_amsdu_len[i] = iwl_mvm_max_amsdu_size(staInfo->mvm, staInfo->sta, i);
else
/*
* Not so elegant, but this will effectively
* prevent AMSDU on this TID
*/
{
staInfo->sta->max_tid_amsdu_len[i] = 1;
}
}
}
static void _rsMngFillNonHtRates(const RS_MNG_STA_INFO_S* staInfo, struct iwl_lq_cmd* lqCmd, U08 i,
RS_MNG_RATE_S* rsMngRate) {
BOOLEAN togglingPossible = _rsMngIsAntSupported(staInfo, rsMngGetDualAntMsk()) &&
btCoexManagerIsAntAvailable(staInfo->mvm, BT_COEX_SHARED_ANT_ID);
if (_rsMngRateGetMode(rsMngRate) != TLC_MNG_MODE_LEGACY) {
U08 currIdx = _rsMngRateGetIdx(rsMngRate);
_rsMngRateSetMode(rsMngRate, TLC_MNG_MODE_LEGACY);
_rsMngRateSetModulation(rsMngRate, RS_MNG_MODUL_LEGACY);
_rsMngRateSetBw(rsMngRate, CHANNEL_WIDTH20);
_rsMngRateSetLdpc(rsMngRate, FALSE);
_rsMngRateSetStbc(rsMngRate, FALSE);
// Always start with the non-shared antenna if it's available. If there's toggling, it
// doesn't make much difference, and if there's no toggling due to bt-coex it promises we'll
// stay on the non-shared antenna.
_rsMngRateSetAnt(rsMngRate, rsMngGetSingleAntMsk(staInfo->config.chainsEnabled));
_rsMngRateSetIdx(rsMngRate, downColMcsToLegacy[currIdx]);
} else {
_rsMngSetLowerRate(staInfo, rsMngRate);
}
for (; i < LQ_MAX_RETRY_NUM; i++) {
lqCmd->rs_table[i] = cpu_to_le32(rsMngRate->rate.rate_n_flags);
_rsMngSetLowerRate(staInfo, rsMngRate);
if (togglingPossible) {
_rsMngRateSetAnt(rsMngRate, (U08)(_rsMngRateGetAnt(rsMngRate) ^ rsMngGetDualAntMsk()));
}
}
}
static void _rsMngBuildRatesTbl(const RS_MNG_STA_INFO_S* staInfo, struct iwl_lq_cmd* lqCmd) {
RS_MNG_RATE_S rsMngRate;
U08 i = 0;
U08 j;
memcpy(&rsMngRate, &staInfo->rateTblInfo.rsMngRate, sizeof(rsMngRate));
if (staInfo->searchBetterTbl) {
// When trying a new column, only the initial rate should be of that column. The rest of the
// table is constructed from the "stable" column.
lqCmd->rs_table[0] = cpu_to_le32(staInfo->searchColData.rsMngRate.rate.rate_n_flags);
i++;
} else if (staInfo->tryingRateUpscale) {
// When trying a higher mcs, try it only once. The next retries will be from the previous
// mcs which is known to be good (otherwise wouldn't be trying a higher one).
lqCmd->rs_table[0] = cpu_to_le32(staInfo->rateTblInfo.rsMngRate.rate.rate_n_flags);
i++;
_rsMngSetLowerRate(staInfo, &rsMngRate);
}
// Fill RS_MNG_RETRY_TABLE_INITIAL_RATE_NUM copies of the best known stable rate
for (j = 0; j < RS_MNG_RETRY_TABLE_INITIAL_RATE_NUM; j++) {
lqCmd->rs_table[i + j] = cpu_to_le32(rsMngRate.rate.rate_n_flags);
}
i += j;
if (!(staInfo->searchBetterTbl || staInfo->tryingRateUpscale) &&
_rsMngSetLowerRate(staInfo, &rsMngRate) != RS_MNG_INVALID_RATE_IDX) {
// In case the first rate is not a test rate, put here RS_MNG_RETRY_TABLE_SECONDARY_RATE_NUM
// copies of the initial rate but mcs-1
// Note that a tpc test window is not treated as a test rate for the purpose of construction
// of the retry table.
for (j = 0; j < RS_MNG_RETRY_TABLE_SECONDARY_RATE_NUM; j++) {
lqCmd->rs_table[i + j] = cpu_to_le32(rsMngRate.rate.rate_n_flags);
}
i += j;
// Now put RS_MNG_RETRY_TABLE_SECONDARY_RATE_20MHZ_NUM copies of the secondary rate with
// 20mhz bandwidth.
_rsMngRateSetBw(&rsMngRate, CHANNEL_WIDTH20);
for (j = 0; j < RS_MNG_RETRY_TABLE_SECONDARY_RATE_20MHZ_NUM; j++) {
lqCmd->rs_table[i + j] = cpu_to_le32(rsMngRate.rate.rate_n_flags);
}
i += j;
}
// Fill the rest of the retry table with non-ht rates
_rsMngFillNonHtRates(staInfo, lqCmd, i, &rsMngRate);
}
static void _rsMngFillLQCmd(RS_MNG_STA_INFO_S* staInfo, struct iwl_lq_cmd* lqCmd) {
int i;
memset(lqCmd, 0, sizeof(*lqCmd));
lqCmd->sta_id = staInfo->mvmsta->sta_id;
if (_rsMngTpcIsActive(staInfo)) {
// reduce Tx power in steps of 3db. Note that currStep == 0 means reduce 3db, hence the '+1'
lqCmd->reduced_tpc = (U08)(RS_MNG_TPC_STEP_SIZE * (staInfo->tpcTable.currStep + 1));
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO, "_rsMngFillLQCmd: reducing tx power by %d db",
lqCmd->reduced_tpc);
}
_rsMngFillAggParamsLQCmd(staInfo, lqCmd);
_rsMngBuildRatesTbl(staInfo, lqCmd);
lqCmd->single_stream_ant_msk = rsMngGetSingleAntMsk(staInfo->config.chainsEnabled);
lqCmd->dual_stream_ant_msk = rsMngGetDualAntMsk();
if (_rsMngIsTestWindow(staInfo)) {
if (IS_RATE_OFDM_HT_VHT_HE_API_M(le32_to_cpu(lqCmd->rs_table[0]))) {
// For 11a/b/g rates, where there are no aggregations anyway, RTS protection just hurts
// the tpt.
lqCmd->rs_table[0] |= cpu_to_le32(RATE_MCS_RTS_REQUIRED_MSK);
// TODO: lqCmd->agg_params.uAggFrameCntInTestWin = RS_MNG_UPSCALE_AGG_FRAME_COUNT;
}
// TODO: lqCmd->general_params.flags |= LINK_QUAL_FLAGS_TEST_WINDOWS_MSK;
}
if (staInfo->mvmsta->tx_protection) {
lqCmd->flags |= LQ_FLAG_USE_RTS_MSK;
}
// When Amsdu's are enabled, enable RTS protection for all rates that use A-MPDUs, since in this
// case there could be really long frames and this should help reduce collisions.
if (staInfo->amsduEnabledSize != RS_MNG_AMSDU_INVALID) {
for (i = 0; i < RS_MNG_AGG_DISABLE_START_TH; i++) {
lqCmd->rs_table[i] |= cpu_to_le32(RATE_MCS_RTS_REQUIRED_MSK);
}
}
}
// rs_update_rate_tbl
static void _rsMngUpdateRateTbl(RS_MNG_STA_INFO_S* staInfo, BOOLEAN notifyHost) {
_rsMngFillLQCmd(staInfo, &staInfo->mvmsta->lq_sta.rs_drv.lq);
iwl_mvm_send_lq_cmd(staInfo->mvm, &staInfo->mvmsta->lq_sta.rs_drv.lq, !staInfo->enabled);
}
static void _rsMngClearWinArr(RS_MNG_WIN_STAT_S* winArr, U08 numWin) {
U08 i;
_memclr(winArr, (sizeof(*winArr) * numWin));
for (i = 0; i < numWin; i++) {
winArr[i].successRatio = RS_MNG_INVALID_VAL;
winArr[i].averageTpt = RS_MNG_INVALID_VAL;
}
}
static void _rsMngClearTblWindows(RS_MNG_STA_INFO_S* staInfo) {
_rsMngClearWinArr(staInfo->rateTblInfo.win, RS_MNG_MAX_RATES_NUM);
_rsMngClearWinArr(staInfo->tpcTable.windows, RS_MNG_TPC_NUM_STEPS);
}
static void _rsMngSetVisitedColumn(RS_MNG_STA_INFO_S* staInfo, RS_MNG_COLUMN_DESC_E colId) {
// to make the code for setting both siso columns in case of stbc simpler, make sure that each
// such pair of columns has only bit 0 different.
BUILD_BUG_ON(!((RS_MNG_COL_SISO_ANT_A ^ RS_MNG_COL_SISO_ANT_B) == 1));
BUILD_BUG_ON(!((RS_MNG_COL_SISO_ANT_A_SGI ^ RS_MNG_COL_SISO_ANT_B_SGI) == 1));
BUILD_BUG_ON(!((RS_MNG_COL_HE_3_2_SISO_ANT_A ^ RS_MNG_COL_HE_3_2_SISO_ANT_B) == 1));
BUILD_BUG_ON(!((RS_MNG_COL_HE_1_6_SISO_ANT_A ^ RS_MNG_COL_HE_1_6_SISO_ANT_B) == 1));
BUILD_BUG_ON(!((RS_MNG_COL_HE_0_8_SISO_ANT_A ^ RS_MNG_COL_HE_0_8_SISO_ANT_B) == 1));
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngSetVisitedColumn: colId %d, stbc allowed %d, visited columns 0x%x", colId,
_rsMngIsStbcSupported(staInfo), staInfo->visitedColumns);
staInfo->visitedColumns |= BIT(colId);
if (rsMngColumns[colId].mode == RS_MNG_MODUL_SISO && _rsMngIsStbcSupported(staInfo)) {
staInfo->visitedColumns |= BIT(colId ^ 1);
}
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO, "_rsMngSetVisitedColumn: visited columns 0x%x",
staInfo->visitedColumns);
}
static U32 _rsMngVhtRateToPhyRate(U32 bw, RS_MCS_E mcs, RS_MNG_GI_E gi, RS_MNG_MODULATION_E nss) {
U32 bitrate;
if (WARN_ON(!(mcs < 10 && bw < MAX_CHANNEL_BW_INDX && nss >= RS_MNG_MODUL_SISO))) {
return 1;
}
bitrate = rsMngVhtRateToBps[bw][mcs];
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO, "_rsMngAmsduRate: bw %d, mcs %d sgi %d nss %d", bw, mcs, gi,
nss);
if (nss == RS_MNG_MODUL_MIMO2) {
bitrate *= 2;
}
if (gi == HT_VHT_SGI) {
bitrate = bitrate + (bitrate / 9);
}
return bitrate >> 20;
}
static U32 _rsMngHeRateToPhyRate(U32 bw, RS_MCS_E mcs, RS_MNG_GI_E gi, RS_MNG_MODULATION_E nss) {
#define RATIO_SCALE 2048
#define MBPS_X_10_TO_KBPS(x) (((x) << 10) / 10)
static const U16 mcsRatios[12] = {
34133, /* 16.666666... */
17067, /* 8.333333... */
11378, /* 5.555555... */
8533, /* 4.166666... */
5689, /* 2.777777... */
4267, /* 2.083333... */
3923, /* 1.851851... */
3413, /* 1.666666... */
2844, /* 1.388888... */
2560, /* 1.250000... */
2276, /* 1.111111... */
2048, /* 1.000000... */
};
static const U32 ratesPerGi[][3] = {
// phy rate in kbps per GI for mcs 11 with 2 ss
// HE_3_2_GI HE_1_6_GI HE_0_8_GI
[CHANNEL_WIDTH20] = {MBPS_X_10_TO_KBPS(2438), MBPS_X_10_TO_KBPS(2708),
MBPS_X_10_TO_KBPS(2868)},
[CHANNEL_WIDTH40] = {MBPS_X_10_TO_KBPS(4875), MBPS_X_10_TO_KBPS(5417),
MBPS_X_10_TO_KBPS(5735)},
[CHANNEL_WIDTH80] = {MBPS_X_10_TO_KBPS(10208), MBPS_X_10_TO_KBPS(11343),
MBPS_X_10_TO_KBPS(12010)},
[CHANNEL_WIDTH160] = {MBPS_X_10_TO_KBPS(20416), MBPS_X_10_TO_KBPS(22685),
MBPS_X_10_TO_KBPS(24019)},
};
U64 tmp;
U32 bitrate;
BOOLEAN isDcm = FALSE;
if (mcs == RS_MCS_0_HE_ER_AND_DCM) {
isDcm = TRUE;
mcs = RS_MCS_0;
}
if (WARN_ON(!(mcs < 12 && bw < MAX_CHANNEL_BW_INDX && gi >= HE_FIRST_GI &&
nss >= RS_MNG_MODUL_SISO))) {
return 1;
}
bitrate = ratesPerGi[bw][gi - HE_FIRST_GI];
tmp = bitrate;
tmp *= RATIO_SCALE;
tmp /= mcsRatios[mcs];
bitrate = (U32)tmp;
if (nss == RS_MNG_MODUL_SISO) {
bitrate /= 2;
}
if (isDcm) {
bitrate /= 2;
}
return bitrate >> 10;
}
static U32 _rsMngRateToPhyRate(TLC_MNG_MODE_E mode, U32 bw, RS_MCS_E mcs, RS_MNG_GI_E gi,
RS_MNG_MODULATION_E nss) {
if (mode == TLC_MNG_MODE_VHT) {
return _rsMngVhtRateToPhyRate(bw, mcs, gi, nss);
}
if (mode == TLC_MNG_MODE_HE) {
return _rsMngHeRateToPhyRate(bw, mcs, gi, nss);
}
return 0;
}
static RS_MNG_TX_AMSDU_SIZE_E _rsMngAmsduSize(const RS_MNG_STA_INFO_S* staInfo, TLC_MNG_MODE_E mode,
U32 bw, RS_MCS_E mcs, RS_MNG_GI_E gi,
RS_MNG_MODULATION_E nss) {
RS_MNG_TX_AMSDU_SIZE_E amsdu_3k, amsdu_5k, amsdu_6k, amsdu_8k;
U32 phyRate = _rsMngRateToPhyRate(mode, bw, mcs, gi, nss);
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngAmsduRate: sta %d, phyRate %d, blacklist bitmap 0x%X",
_rsMngStaInfoToStaId(staInfo), phyRate, staInfo->amsduBlacklist);
amsdu_3k = RS_MNG_AMSDU_3500B;
amsdu_5k = RS_MNG_AMSDU_5000B;
if (staInfo->amsduBlacklist) {
// If we disabled 3k AMSDU - don't use it at all
if (staInfo->amsduBlacklist & BIT(RS_MNG_AMSDU_3500B)) {
amsdu_3k = RS_MNG_AMSDU_INVALID;
}
// If we disabled some amsdu size, use a smaller size.
// Note that smaller sizes that are blacklisted as well will still not be used.
if (staInfo->amsduBlacklist & BIT(RS_MNG_AMSDU_5000B)) {
amsdu_5k = amsdu_3k;
}
}
if (mode == TLC_MNG_MODE_HE) {
amsdu_6k = RS_MNG_AMSDU_6500B;
amsdu_8k = RS_MNG_AMSDU_8000B;
if (staInfo->amsduBlacklist & BIT(RS_MNG_AMSDU_6500B)) {
amsdu_6k = amsdu_5k;
}
if (staInfo->amsduBlacklist & BIT(RS_MNG_AMSDU_8000B)) {
amsdu_8k = amsdu_6k;
}
if (phyRate > RS_MNG_AMSDU_HE_8K_THRESHOLD) {
return amsdu_8k;
}
if (phyRate > RS_MNG_AMSDU_HE_6K_THRESHOLD) {
return amsdu_6k;
}
}
if (phyRate > RS_MNG_AMSDU_5K_THRESHOLD) {
return amsdu_5k;
}
if (phyRate > RS_MNG_AMSDU_3K_THRESHOLD) {
return amsdu_3k;
}
return RS_MNG_AMSDU_INVALID;
}
static const TPT_BY_RATE_ARR* _rsMngGetExpectedTptTable(const RS_MNG_COL_ELEM_S* col,
TLC_MNG_CH_WIDTH_E bw, BOOLEAN isAgg) {
U32 nss;
U32 gi;
if (col->mode == RS_MNG_MODUL_LEGACY) {
return &expectedTptNonHt;
}
nss = col->mode == RS_MNG_MODUL_SISO ? RS_MNG_SISO : RS_MNG_MIMO;
switch (col->gi) {
case HT_VHT_NGI:
gi = RS_MNG_NGI;
break;
case HT_VHT_SGI:
gi = RS_MNG_SGI;
break;
case HE_3_2_GI:
gi = RS_MNG_GI_3_2;
break;
case HE_1_6_GI:
gi = RS_MNG_GI_1_6;
break;
case HE_0_8_GI:
gi = RS_MNG_GI_0_8;
break;
default:
WARN_ON(1);
gi = 0;
}
DBG_PRINTF(
UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetExpectedTptTable: expected Tpt table - isHE %d, isAgg %d, BW %d, GI %d, NSS %d",
col->gi >= HE_FIRST_GI, isAgg, bw, gi, nss);
if (col->gi < HE_FIRST_GI) {
return &expectedTptHtVht[isAgg][bw][gi][nss];
}
return &expectedTptHe[isAgg][bw][gi][nss];
}
static U32 _rsMngGetExpectedTpt(const RS_MNG_STA_INFO_S* staInfo, const RS_MNG_COL_ELEM_S* col,
TLC_MNG_CH_WIDTH_E bw, BOOLEAN isAgg, RS_MCS_E rateIdx) {
const TPT_BY_RATE_ARR* expectedTptTable = _rsMngGetExpectedTptTable(col, bw, isAgg);
U32 ret;
if (expectedTptTable == &expectedTptNonHt) {
return (*expectedTptTable)[rateIdx];
}
if (rateIdx == RS_MCS_0_HE_ER_AND_DCM) {
// rateIdx == RS_MCS_0_HE_ER_AND_DCM. DCM cuts expected tpt in half.
// TODO: add an additional small penalty for ER
return (*expectedTptTable)[RS_MCS_0] / 2;
}
ret = (*expectedTptTable)[rateIdx];
if (staInfo->amsduSupport && staInfo->mvmsta->agg_tids && staInfo->amsduInAmpdu) {
switch (staInfo->amsduEnabledSize) {
case RS_MNG_AMSDU_8000B:
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetExpectedTpt: adding 50%% thanks to 8k amsdu");
ret += (ret / 2);
break;
case RS_MNG_AMSDU_6500B:
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetExpectedTpt: adding 37.5%% thanks to 6.5k amsdu");
ret += (ret / 4) + (ret / 8);
break;
case RS_MNG_AMSDU_5000B:
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetExpectedTpt: adding 25%% thanks to 5k amsdu");
ret += (ret / 4);
break;
case RS_MNG_AMSDU_3500B:
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetExpectedTpt: adding 12.5%% thanks to 3.5k amsdu");
ret += (ret / 8);
break;
default:
break;
}
}
return ret;
}
static BOOLEAN _isAvgTptCalcPossible(RS_MNG_WIN_STAT_S* win) {
return ((win->successCounter >= RS_MNG_RATE_MIN_SUCCESS_TH) ||
((win->framesCounter - win->successCounter) >= RS_MNG_RATE_MIN_FAILURE_TH));
}
// rs_get_rate_action
//
// return after every if. so the 'strength' of the conditions are as follows :
//
// Downscale if:
// - the current window success ratio <= 15% || avg tpt for this window is 0
// Upscale if:
// - low and high tpt (tpt for the next/prev rates) are invalid *but* the next rate is valid
// - low_tpt < current_tpt (tpt for prev rate < avg tpt in current window ) *and*
// next rate is valid although it's tpt isn't
// - high tpt > current tpt
// Stay if:
// - low and high tpt < current tpt
//----- but if none of the above conditions are met. for example - due to invalid high/low tpt :
// if low_tpt > current tpt or low tpt is invalid, but the lower index entry is :
// - if low is valid:
// Stay if:
// - the current suceess rate is >= 85% (good enough)
// - current tpt > expected tpt at [low] (was supposed to do downscale, but current tpt is good
// enough although the success rate isn't. so we are optomistics)
// Downscale:
// - both above are not met
// - low is invalid
static RS_MNG_ACTION_E _rsMngGetScaleAction(const RS_MNG_STA_INFO_S* staInfo,
const RS_MNG_WIN_STAT_S* currWin, U32 lowerRateIdx,
U32 higherRateIdx) {
const RS_MNG_TBL_INFO_S* tblInfo = &staInfo->rateTblInfo;
U32 currTpt;
U32 lowTpt;
U32 highTpt;
RS_MNG_ACTION_E action = RS_MNG_ACTION_STAY;
enum {
RS_MNG_SCALE_REASON_BELOW_FORCE_DECREASE,
RS_MNG_SCALE_REASON_NO_DATA_ON_HIGHER_RATE,
RS_MNG_SCALE_REASON_HIGHER_RATE_HAS_HIGHER_TPT,
RS_MNG_SCALE_REASON_CURRENT_RATE_HAS_HIGHEST_TPT,
RS_MNG_SCALE_REASON_SR_ABOVE_NO_DECREASE_THRESHOLD,
RS_MNG_SCALE_REASON_LOWER_RATE_TPT_UNKOWN_OR_BETTER,
RS_MNG_SCALE_REASON_DEFAULT,
};
currTpt = currWin->averageTpt;
lowTpt = ((lowerRateIdx == RS_MNG_INVALID_RATE_IDX) ? RS_MNG_INVALID_VAL
: tblInfo->win[lowerRateIdx].averageTpt);
highTpt = ((higherRateIdx == RS_MNG_INVALID_RATE_IDX) ? RS_MNG_INVALID_VAL
: tblInfo->win[higherRateIdx].averageTpt);
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction:\ncurrTpt: %d, successRatio: %d,\nlowerRateIdx: %d, lowTpt: "
"%d,\nhigherRateIdx: %d, highTpt: %d",
currTpt, currWin->successRatio, lowerRateIdx, lowTpt, higherRateIdx, highTpt);
// current Success ratio is insufficient or Tpt for the current window is 0 => downscale
if ((currWin->successRatio <= RS_MNG_PERCENT(RS_MNG_SR_FORCE_DECREASE)) || (0 == currTpt)) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: DOWNSCALE due to insufficient success ratio or 0 tpt");
action = RS_MNG_ACTION_DOWNSCALE;
goto out;
}
// No Tpt data about high/low rate => upscale
if ((RS_MNG_INVALID_VAL == lowTpt) && (RS_MNG_INVALID_VAL == highTpt) &&
(RS_MNG_INVALID_RATE_IDX != higherRateIdx)) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: UPSCALE due to no data about higher or lower rates");
action = RS_MNG_ACTION_UPSCALE;
goto out;
}
// if there's no Tpt data about the higerRateIdx but the Tpt for the lowerRateIdx is worse then
// the curr tpt => Upscale
if (((RS_MNG_INVALID_VAL == highTpt) && (RS_MNG_INVALID_RATE_IDX != higherRateIdx)) &&
((RS_MNG_INVALID_VAL != lowTpt) && (lowTpt < currTpt))) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: UPSCALE due to no data on higher rate and lower rate has "
"worse tpt");
action = RS_MNG_ACTION_UPSCALE;
goto out;
}
// if higherRateIdx tpt > currTpt => upscale
if ((RS_MNG_INVALID_VAL != highTpt) && (highTpt > currTpt)) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: UPSCALE due to higher rate having higher tpt");
action = RS_MNG_ACTION_UPSCALE;
goto out;
}
// if Tpt for the higherRateIdx and for LowerRateIdx are both worse then the current Tpt => stay
if (((RS_MNG_INVALID_VAL != highTpt) && (highTpt < currTpt)) &&
((RS_MNG_INVALID_VAL != lowTpt) && (lowTpt < currTpt))) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: STAY due to current rate having better tpt that both "
"higher and lower rates");
action = RS_MNG_ACTION_STAY;
goto out;
}
// If Tpt for LowerRateIdx > currTpt, or it is unknown but lowerRateIdx is valid
if (((RS_MNG_INVALID_VAL != lowTpt) && (lowTpt > currTpt)) ||
((RS_MNG_INVALID_VAL == lowTpt) && (RS_MNG_INVALID_RATE_IDX != lowerRateIdx))) {
U32 lowerRateExpectedTpt = _rsMngGetExpectedTpt(staInfo, &rsMngColumns[tblInfo->column],
_rsMngRateGetBw(&tblInfo->rsMngRate),
!!(staInfo->mvmsta->agg_tids), lowerRateIdx);
// if CurrWin success ratio reached the no decrease TH, or currTpt is higher then expected
// Tpt => stay
if ((RS_MNG_INVALID_RATE_IDX != lowerRateIdx) &&
((currWin->successRatio >= RS_MNG_PERCENT(RS_MNG_SR_NO_DECREASE)) ||
(currTpt > lowerRateExpectedTpt))) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: STAY due to lower rate having expected tpt lower "
"than current tpt or current success ratio is above the 'no-decrease' "
"threshold. lower rate expected tpt: %d",
lowerRateExpectedTpt);
action = RS_MNG_ACTION_STAY;
goto out;
}
// curr SR is insufficient and either lowTpt is valid and > currTpt or lowerRateIdx is valid
// => downscale
else {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetScaleAction: DOWNSCALE due to low success ratio or lower rate "
"having higher tpt than current rate. lower rate expected tpt: %d",
lowerRateExpectedTpt);
action = RS_MNG_ACTION_DOWNSCALE;
goto out;
}
}
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO, "_rsMngGetScaleAction: STAY (default)");
action = RS_MNG_ACTION_STAY;
out:
return action;
}
// return: TRUE if there is a better start rate, so need to send LQ command
// newIdx: valid only if the return value is true
// RS_MNG_INVALID_RATE_IDX - if need to keep using the current index
// new index to use - if there is another rate that will provide better tpt / tpc
static RS_MNG_ACTION_E _rsMngSearchBetterStartRate(const RS_MNG_STA_INFO_S* staInfo,
RS_MNG_WIN_STAT_S* currWin,
const RS_MNG_RATE_S* currRate, U08* newIdx) {
U08 lowerSuppRateIdx;
U08 higherSuppRateIdx;
RS_MNG_ACTION_E scaleAction;
lowerSuppRateIdx = _rsMngGetAdjacentRateIdx(staInfo, currRate, GET_LOWER_SUPPORTED_RATE);
higherSuppRateIdx = _rsMngGetAdjacentRateIdx(staInfo, currRate, GET_HIGHER_SUPPORTED_RATE);
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngSearchBetterStartRate: curr rate idx: %d, lower: %d, higher: %d. supported "
"rates mask: 0x%x",
_rsMngRateGetIdx(currRate), lowerSuppRateIdx, higherSuppRateIdx, supportedRatesMsk);
scaleAction = _rsMngGetScaleAction(staInfo, currWin, lowerSuppRateIdx, higherSuppRateIdx);
// FMAC TODO - add 'fix' in case we are in MIMO and BT doesn't 'allow' MIMO ? (currently a dead
// code in fmac)
// Set the new rate index + tx power reduction, if needed
switch (scaleAction) {
case RS_MNG_ACTION_STAY:
if (staInfo->rsMngState == RS_MNG_STATE_STAY_IN_COLUMN) {
// TODO - add tpc support
// rs_tpc_perform(sta, lq_sta, tbl);
}
break;
case RS_MNG_ACTION_DOWNSCALE:
if (RS_MNG_INVALID_RATE_IDX != lowerSuppRateIdx) {
// TODO - add tpc
*newIdx = lowerSuppRateIdx;
}
// else - already at the lowest possible rate -> can't downscale
else {
scaleAction = RS_MNG_ACTION_STAY;
}
break;
case RS_MNG_ACTION_UPSCALE:
if (RS_MNG_INVALID_RATE_IDX != higherSuppRateIdx) {
// TODO - add tpc
*newIdx = higherSuppRateIdx;
}
// else - already at the highest possible rate -> can't upscale
else {
scaleAction = RS_MNG_ACTION_STAY;
}
break;
default:
// TODO add assert?
break;
}
return scaleAction;
}
static U08 _rsMngGetLowestSupportedRate(const RS_MNG_STA_INFO_S* staInfo,
RS_MNG_MODULATION_E modulation, U32 bw,
U16 supportedRates) {
if (modulation != RS_MNG_MODUL_LEGACY && staInfo->config.bestSuppMode == TLC_MNG_MODE_HE &&
bw == CHANNEL_WIDTH20 && _rsMngIsDcmSupported(staInfo, modulation == RS_MNG_MODUL_MIMO2)) {
return RS_MCS_0_HE_ER_AND_DCM;
}
return (U08)LSB2ORD(supportedRates);
}
//
// Returns the index of the lowest rate in the given column with expected tpt higher
// than the target tpt.
//
static U08 _rsMngGetBestRate(const RS_MNG_STA_INFO_S* staInfo, const RS_MNG_TBL_INFO_S* activeTbl,
const RS_MNG_COL_ELEM_S* col, U32 bw, U32 targetTpt) {
U16 supportedRates = _rsMngGetSupportedRatesByModeAndBw(staInfo, col->mode, bw);
U08 rateIdx = _rsMngGetLowestSupportedRate(staInfo, col->mode, bw, supportedRates);
U32 expectedTpt = 0;
while (rateIdx != RS_MNG_INVALID_RATE_IDX) {
expectedTpt = _rsMngGetExpectedTpt(staInfo, col, bw, !!staInfo->mvmsta->agg_tids, rateIdx);
if (targetTpt <= expectedTpt) {
break;
}
rateIdx = _rsMngGetHigherRateIdx(rateIdx, supportedRates);
}
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetBestRate: best rateIdx %d. targetTpt: %d, new expected tpt: %d", rateIdx,
targetTpt, expectedTpt);
return rateIdx;
}
static BOOLEAN _rsMngIsColAllowed(const RS_MNG_STA_INFO_S* staInfo, U32 bw,
const RS_MNG_COL_ELEM_S* nextCol) {
int i;
for (i = 0; i < MAX_COLUMN_CHECKS; i++) {
ALLOW_COL_FUNC_F allowColFunc = nextCol->checks[i];
if (allowColFunc && !allowColFunc(staInfo, bw, nextCol)) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO, "_rsMngIsColAllowed: Function[%d] check failed", i);
return FALSE;
}
}
return TRUE;
}
// rs_get_next_column
// return column with expected better tpt
// or invalid column if such doesn't exist
//
// flow:
// get next column according to rs_tx_columns [index].next_columns[].
// if the next column is invalid - continue to next column in the next_columns list
// if already visited the next column - continue to next column in the next_columns list
// if the chosen antenna is not supported - continue to next column in the next_columns list
// if one of the function checks failed - continue to next column in the next_columns list
// if there is no expected throughput in the table - continue to next column in the next_columns
// list
// now we have the next column.
// get expected tpt table according to siso/mimo + BW + /GI/SGI/AGG/SGI+AGG / legacy (one table)
// compare the current tpt with max expected tpt in this table.
// if current tpt >= max. => continue to next column
//
// else - return the found column id.
//
static RS_MNG_COLUMN_DESC_E _rsMngGetNextColId(const RS_MNG_STA_INFO_S* staInfo,
const RS_MNG_TBL_INFO_S* tblInfo, U32 targetTpt,
U32* bw, U08* rateIdx) {
const RS_MNG_COL_ELEM_S* currCol = &rsMngColumns[tblInfo->column];
const RS_MNG_COL_ELEM_S* nextCol;
RS_MNG_COLUMN_DESC_E nextColId = RS_MNG_COL_INVALID; // for compilation. won't be used
int i;
// Check that the defines' value allow to assume that we can add NON_SHARED_ANT_RFIC_ID to
// RS_MNG_COL_SISO_ANT_A to get the shared antenna
BUILD_BUG_ON(!(RS_MNG_COL_SISO_ANT_A + 1 == RS_MNG_COL_SISO_ANT_B));
BUILD_BUG_ON(!(RS_MNG_COL_SISO_ANT_A_SGI + 1 == RS_MNG_COL_SISO_ANT_B_SGI));
BUILD_BUG_ON(!(RS_MNG_COL_HE_3_2_SISO_ANT_A + 1 == RS_MNG_COL_HE_3_2_SISO_ANT_B));
BUILD_BUG_ON(!(RS_MNG_COL_HE_1_6_SISO_ANT_A + 1 == RS_MNG_COL_HE_1_6_SISO_ANT_B));
BUILD_BUG_ON(!(RS_MNG_COL_HE_0_8_SISO_ANT_A + 1 == RS_MNG_COL_HE_0_8_SISO_ANT_B));
for (i = 0; i < MAX_NEXT_COLUMNS; i++) {
nextColId = currCol->nextCols[i];
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO, "_rsMngGetNextColId: Checking nextCol %d (column id %d)",
i, nextColId);
if (RS_MNG_COL_INVALID == nextColId) {
DBG_PRINTF(UT, TLC_OFFLOAD_DBG, INFO,
"_rsMngGetNextColId: invalid column. next columns are also invalid, so break");
break; // if column is invalid, all the following ones will be invalid as well
}
if (0 == i && RS_MNG_MODUL_MIMO2 == currCol->mode) {
nextColId += NON_SHARED_ANT_RFIC_ID;
}