summaryrefslogtreecommitdiff
path: root/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/devkit/rt5572drv/MODULE/rate_ctrl')
-rw-r--r--cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_ags.c1375
-rw-r--r--cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_grp.c1621
-rw-r--r--cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c899
-rw-r--r--cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/ra_ctrl.c1751
4 files changed, 5646 insertions, 0 deletions
diff --git a/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_ags.c b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_ags.c
new file mode 100644
index 0000000000..3e5833a99d
--- /dev/null
+++ b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_ags.c
@@ -0,0 +1,1375 @@
+/****************************************************************************
+ * Ralink Tech Inc.
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************/
+
+/****************************************************************************
+
+ Abstract:
+
+ All related AGS (Adaptive Group Switching) function body.
+
+***************************************************************************/
+
+#define MODULE_AGS
+#include "rt_config.h"
+
+#ifdef AGS_SUPPORT
+
+
+/* */
+/* AGS: 1x1 HT-capable rate table */
+/* */
+ UCHAR AGS1x1HTRateTable[] =
+ {
+ /* */
+ /* [Item no.] [Mode]* [CurrMCS] [TrainUp] [TrainDown] [downMCS ] [upMCS3] [upMCS2] [upMCS1] */
+ /* */
+ /* [Mode]*: */
+ /* bit0: STBC */
+ /* bit1: Short GI */
+ /* bit2: BW */
+ /* bit4~bit5: Mode (0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
+ /* */
+ 0x09, 0x08, 0, 0, 0, 0, 0, 0, 0, /* Initial used item after association: the number of rate indexes, the initial mcs */
+ 0x00, 0x21, 0, 30, 101, 0, 16, 8, 1, /* MCS 0 */
+ 0x01, 0x21, 1, 20, 50, 0, 16, 9, 2, /* MCS 1 */
+ 0x02, 0x21, 2, 20, 50, 1, 17, 9, 3, /* MCS 2 */
+ 0x03, 0x21, 3, 15, 50, 2, 17, 10, 4, /* MCS 3 */
+ 0x04, 0x21, 4, 15, 30, 3, 18, 11, 5, /* MCS 4 */
+ 0x05, 0x21, 5, 10, 25, 4, 18, 12, 6, /* MCS 5 */
+ 0x06, 0x21, 6, 8, 14, 5, 19, 12, 7, /* MCS 6 */
+ 0x07, 0x21, 7, 8, 14, 6, 19, 12, 8, /* MCS 7 */
+ 0x08, 0x23, 7, 8, 14, 7, 19, 12, 8, /* MCS 7 + Short GI */
+};
+
+
+
+/* */
+/* AGS: 2x2 HT-capable rate table */
+/* */
+ UCHAR AGS2x2HTRateTable[] =
+ {
+ /* */
+ /* [Item no.] [Mode]* [CurrMCS] [TrainUp] [TrainDown] [downMCS ] [upMCS3] [upMCS2] [upMCS1] */
+ /* */
+ /* [Mode]*: */
+ /* bit0: STBC */
+ /* bit1: Short GI */
+ /* bit2: BW */
+ /* bit4~bit5: Mode (0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
+ /* */
+ 0x11, 0x10, 0, 0, 0, 0, 0, 0, 0, /* Initial used item after association: the number of rate indexes, the initial mcs */
+ 0x00, 0x21, 0, 30, 101, 0, 16, 8, 1, /* MCS 0 */
+ 0x01, 0x21, 1, 20, 50, 0, 16, 9, 2, /* MCS 1 */
+ 0x02, 0x21, 2, 20, 50, 1, 17, 9, 3, /* MCS 2 */
+ 0x03, 0x21, 3, 15, 50, 2, 17, 10, 4, /* MCS 3 */
+ 0x04, 0x21, 4, 15, 30, 3, 18, 11, 5, /* MCS 4 */
+ 0x05, 0x21, 5, 10, 25, 4, 18, 12, 6, /* MCS 5 */
+ 0x06, 0x21, 6, 8, 14, 5, 19, 12, 7, /* MCS 6 */
+ 0x07, 0x21, 7, 8, 14, 6, 19, 12, 7, /* MCS 7 */
+ 0x08, 0x20, 8, 30, 50, 0, 16, 9, 2, /* MCS 8 */
+ 0x09, 0x20, 9, 20, 50, 8, 17, 10, 4, /* MCS 9 */
+ 0x0A, 0x20, 10, 20, 50, 9, 18, 11, 5, /* MCS 10 */
+ 0x0B, 0x20, 11, 15, 30, 10, 18, 12, 6, /* MCS 11 */
+ 0x0C, 0x20, 12, 15, 30, 11, 20, 13, 12, /* MCS 12 */
+ 0x0D, 0x20, 13, 8, 20, 12, 20, 14, 13, /* MCS 13 */
+ 0x0E, 0x20, 14, 8, 18, 13, 21, 15, 14, /* MCS 14 */
+ 0x0F, 0x20, 15, 8, 25, 14, 21, 16, 15, /* MCS 15 */
+ 0x10, 0x22, 15, 8, 25, 15, 21, 16, 16, /* MCS 15 + Short GI */
+};
+
+
+
+/* */
+/* AGS: 3x3 HT-capable rate table */
+/* */
+ UCHAR AGS3x3HTRateTable[] =
+ {
+ /* */
+ /* [Item no.] [Mode]* [CurrMCS] [TrainUp] [TrainDown] [downMCS ] [upMCS3] [upMCS2] [upMCS1] */
+ /* */
+ /* [Mode]*: */
+ /* bit0: STBC */
+ /* bit1: Short GI */
+ /* bit2: BW */
+ /* bit4~bit5: Mode (0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
+ /* */
+ 0x19, 0x18, 0, 0, 0, 0, 0, 0, 0, /* Initial used item after association: the number of rate indexes, the initial mcs */
+ 0x00, 0x21, 0, 30, 101, 0, 16, 8, 1, /* MCS 0 */
+ 0x01, 0x21, 1, 20, 50, 0, 16, 9, 2, /* MCS 1 */
+ 0x02, 0x21, 2, 20, 50, 1, 17, 9, 3, /* MCS 2 */
+ 0x03, 0x21, 3, 15, 50, 2, 17, 10, 4, /* MCS 3 */
+ 0x04, 0x21, 4, 15, 30, 3, 18, 11, 5, /* MCS 4 */
+ 0x05, 0x21, 5, 10, 25, 4, 18, 12, 6, /* MCS 5 */
+ 0x06, 0x21, 6, 8, 14, 5, 19, 12, 7, /* MCS 6 */
+ 0x07, 0x21, 7, 8, 14, 6, 19, 12, 7, /* MCS 7 */
+ 0x08, 0x20, 8, 30, 50, 0, 16, 9, 2, /* MCS 8 */
+ 0x09, 0x20, 9, 20, 50, 8, 17, 10, 4, /* MCS 9 */
+ 0x0A, 0x20, 10, 20, 50, 9, 18, 11, 5, /* MCS 10 */
+ 0x0B, 0x20, 11, 15, 30, 10, 18, 12, 6, /* MCS 11 */
+ 0x0C, 0x20, 12, 15, 30, 11, 20, 13, 12, /* MCS 12 */
+ 0x0D, 0x20, 13, 8, 20, 12, 20, 14, 13, /* MCS 13 */
+ 0x0E, 0x20, 14, 8, 18, 13, 21, 15, 14, /* MCS 14 */
+ 0x0F, 0x20, 15, 8, 14, 14, 21, 15, 15, /* MCS 15 */
+ 0x10, 0x20, 16, 30, 50, 8, 17, 9, 3, /* MCS 16 */
+ 0x11, 0x20, 17, 20, 50, 16, 18, 11, 5, /* MCS 17 */
+ 0x12, 0x20, 18, 20, 50, 17, 19, 12, 7, /* MCS 18 */
+ 0x13, 0x20, 19, 15, 30, 18, 20, 13, 19, /* MCS 19 */
+ 0x14, 0x20, 20, 15, 30, 19, 21, 15, 20, /* MCS 20 */
+ 0x15, 0x20, 21, 8, 20, 20, 22, 21, 21, /* MCS 21 */
+ 0x16, 0x20, 22, 8, 20, 21, 23, 22, 22, /* MCS 22 */
+ 0x17, 0x20, 23, 6, 18, 22, 24, 23, 23, /* MCS 23 */
+ 0x18, 0x22, 23, 6, 14, 23, 24, 24, 24, /* MCS 23 + Short GI */
+};
+
+
+
+
+INT Show_AGS_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[1];
+ UINT32 IdQuality;
+
+
+ DBGPRINT(RT_DEBUG_OFF, ("MCS Group\t\tMCS Index\n"));
+ DBGPRINT(RT_DEBUG_OFF, ("%d\t\t\t%d\n\n", pEntry->AGSCtrl.MCSGroup, pEntry->CurrTxRateIndex));
+
+ DBGPRINT(RT_DEBUG_OFF, ("MCS Quality:\n"));
+ for(IdQuality=0; IdQuality<=23; IdQuality++)
+ DBGPRINT(RT_DEBUG_OFF, ("%02d\t\t%d\n", IdQuality, pEntry->TxQuality[IdQuality]));
+
+ return TRUE;
+}
+
+
+/* */
+/* The dynamic Tx rate switching for AGS (Adaptive Group Switching) */
+/* */
+/* Parameters */
+/* pAd: The adapter data structure */
+/* pEntry: Pointer to a caller-supplied variable in which points to a MAC table entry */
+/* pTable: Pointer to a caller-supplied variable in wich points to a Tx rate switching table */
+/* TableSize: The size, in bytes, of the specified Tx rate switching table */
+/* pAGSStatisticsInfo: Pointer to a caller-supplied variable in which points to the statistics information */
+/* */
+/* Return Value: */
+/* None */
+/* */
+VOID MlmeDynamicTxRateSwitchingAGS(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PUCHAR pTable,
+ IN UCHAR TableSize,
+ IN PAGS_STATISTICS_INFO pAGSStatisticsInfo,
+ IN UCHAR InitTxRateIdx)
+{
+ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
+ BOOLEAN bTxRateChanged = TRUE, bUpgradeQuality = FALSE;
+ PRTMP_TX_RATE_SWITCH_AGS pCurrTxRate = NULL;
+ PRTMP_TX_RATE_SWITCH pNextTxRate = NULL;
+ UCHAR TrainUp = 0, TrainDown = 0;
+ CHAR RssiOffset = 0;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n\nAGS: ---> %s\n", __FUNCTION__));
+
+ DBGPRINT(RT_DEBUG_TRACE, ("%s: QuickAGS: AccuTxTotalCnt = %lu, TxSuccess = %lu, TxRetransmit = %lu, TxFailCount = %lu, TxErrorRatio = %lu\n",
+ __FUNCTION__,
+ pAGSStatisticsInfo->AccuTxTotalCnt,
+ pAGSStatisticsInfo->TxSuccess,
+ pAGSStatisticsInfo->TxRetransmit,
+ pAGSStatisticsInfo->TxFailCount,
+ pAGSStatisticsInfo->TxErrorRatio));
+
+ /* for 3*3, 1st time, pEntry->CurrTxRateIndex = 24 in StaAddMacTableEntry() */
+ CurrRateIdx = pEntry->CurrTxRateIndex;
+
+ if (CurrRateIdx >= TableSize)
+ {
+ CurrRateIdx = TableSize - 1;
+ }
+
+ pCurrTxRate = (PRTMP_TX_RATE_SWITCH_AGS)(&pTable[(CurrRateIdx + 1) *
+ SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+
+ /* */
+ /* Select the next upgrade rate and the next downgrade rate, if any */
+ /* */
+ do
+ {
+ if (InitTxRateIdx == AGS3x3HTRateTable[1])
+ {
+ /* 3*3 table */
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: pEntry->AGSCtrl.MCSGroup = %d, TxQuality2[%d] = %d, "
+ "TxQuality1[%d] = %d, TxQuality0[%d] = %d, pCurrTxRate->upMcs1 = %d, "
+ "pCurrTxRate->ItemNo = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup,
+ pCurrTxRate->upMcs3,
+ pEntry->TxQuality[pCurrTxRate->upMcs3],
+ pCurrTxRate->upMcs2,
+ pEntry->TxQuality[pCurrTxRate->upMcs2],
+ pCurrTxRate->upMcs1,
+ pEntry->TxQuality[pCurrTxRate->upMcs1],
+ pCurrTxRate->upMcs1,
+ pCurrTxRate->ItemNo));
+
+ /* */
+ /* 3x3 peer device (Adhoc, DLS or AP) */
+ /* */
+ /* for 3*3, pEntry->AGSCtrl.MCSGroup = 0, 3, 3, 3, ... */
+ switch (pEntry->AGSCtrl.MCSGroup)
+ {
+ case 0: /* MCS selection in round robin policy (different MCS group) */
+ {
+ UpRateIdx = pCurrTxRate->upMcs3;
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> MCSGroup = 0; UpRateIdx = %d in group 3 is better.\n",
+ UpRateIdx));
+
+ /* MCS group #2 has better Tx quality */
+ if ((pEntry->TxQuality[UpRateIdx] >
+ pEntry->TxQuality[pCurrTxRate->upMcs2]) &&
+ (pCurrTxRate->upMcs2 != pCurrTxRate->ItemNo))
+ {
+ /* quality for group 2 is better */
+ UpRateIdx = pCurrTxRate->upMcs2;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> MCSGroup = 0; UpRateIdx = %d in group 2 is better.\n",
+ UpRateIdx));
+ }
+
+ /* MCS group #1 has better Tx quality */
+ if ((pEntry->TxQuality[UpRateIdx] >
+ pEntry->TxQuality[pCurrTxRate->upMcs1]) &&
+ (pCurrTxRate->upMcs1 != pCurrTxRate->ItemNo))
+ {
+ /* quality for group 1 is better */
+ UpRateIdx = pCurrTxRate->upMcs1;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> MCSGroup = 0; UpRateIdx = %d in group 1 is better.\n",
+ UpRateIdx));
+ }
+ }
+ break;
+
+ case 3:
+ {
+ UpRateIdx = pCurrTxRate->upMcs3;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> MCSGroup = 3; UpRateIdx = %d\n",
+ UpRateIdx));
+ }
+ break;
+
+ case 2:
+ {
+ UpRateIdx = pCurrTxRate->upMcs2;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> MCSGroup = 2; UpRateIdx = %d\n",
+ UpRateIdx));
+ }
+ break;
+
+ case 1:
+ {
+ UpRateIdx = pCurrTxRate->upMcs1;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> MCSGroup = 1; UpRateIdx = %d\n",
+ UpRateIdx));
+ }
+ break;
+
+ default:
+ {
+ DBGPRINT_RAW(RT_DEBUG_ERROR,
+ ("%s: AGS: [3x3 peer device (Adhoc, DLS or AP)], "
+ "Incorrect MCS group, pEntry->AGSCtrl.MCSGroup = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup));
+ }
+ break;
+ }
+
+ if ((pEntry->AGSCtrl.MCSGroup == 0) &&
+ (((pEntry->TxQuality[pCurrTxRate->upMcs3] >
+ pEntry->TxQuality[pCurrTxRate->upMcs2]) &&
+ (pCurrTxRate->upMcs2 != pCurrTxRate->ItemNo)) ||
+ ((pEntry->TxQuality[pCurrTxRate->upMcs3] >
+ pEntry->TxQuality[pCurrTxRate->upMcs1]) &&
+ (pCurrTxRate->upMcs1 != pCurrTxRate->ItemNo))))
+ {
+ /* quality of group 2 or 1 is better than group 3 */
+ /* just show debug information here */
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: ###################################################"
+ "#######################\n",
+ __FUNCTION__));
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: [3x3 peer device (Adhoc, DLS or AP)], Before - "
+ "pEntry->AGSCtrl.MCSGroup = %d, TxQuality2[%d] = %d, "
+ "TxQuality1[%d] = %d, TxQuality0[%d] = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup,
+ pCurrTxRate->upMcs3,
+ pEntry->TxQuality[pCurrTxRate->upMcs3],
+ pCurrTxRate->upMcs2,
+ pEntry->TxQuality[pCurrTxRate->upMcs2],
+ pCurrTxRate->upMcs1,
+ pEntry->TxQuality[pCurrTxRate->upMcs1]));
+ }
+ }
+ else if (InitTxRateIdx == AGS2x2HTRateTable[1])
+ {
+ /* 2*2 table */
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: pEntry->AGSCtrl.MCSGroup = %d, TxQuality1[%d] = %d, "
+ "TxQuality0[%d] = %d, pCurrTxRate->upMcs1 = %d, "
+ "pCurrTxRate->ItemNo = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup,
+ pCurrTxRate->upMcs2,
+ pEntry->TxQuality[pCurrTxRate->upMcs2],
+ pCurrTxRate->upMcs1,
+ pEntry->TxQuality[pCurrTxRate->upMcs1],
+ pCurrTxRate->upMcs1,
+ pCurrTxRate->ItemNo));
+
+ /* */
+ /* 2x2 peer device (Adhoc, DLS or AP) */
+ /* */
+ switch (pEntry->AGSCtrl.MCSGroup)
+ {
+ case 0: /* MCS selection in round robin policy */
+ {
+ UpRateIdx = pCurrTxRate->upMcs2;
+
+ /* MCS group #1 has better Tx quality */
+ if ((pEntry->TxQuality[UpRateIdx] >
+ pEntry->TxQuality[pCurrTxRate->upMcs1]) &&
+ (pCurrTxRate->upMcs1 != pCurrTxRate->ItemNo))
+ {
+ UpRateIdx = pCurrTxRate->upMcs1;
+ }
+ }
+ break;
+
+ case 2:
+ {
+ UpRateIdx = pCurrTxRate->upMcs2;
+ }
+ break;
+
+ case 1:
+ {
+ UpRateIdx = pCurrTxRate->upMcs1;
+ }
+ break;
+
+ default:
+ {
+ DBGPRINT_RAW(RT_DEBUG_ERROR,
+ ("%s: AGS: [2x2 peer device (Adhoc, DLS or AP)], "
+ "Incorrect MCS group, pEntry->AGSCtrl.MCSGroup = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup));
+ }
+ break;
+ }
+
+ if ((pEntry->AGSCtrl.MCSGroup == 0) &&
+ ((pEntry->TxQuality[pCurrTxRate->upMcs2] >
+ pEntry->TxQuality[pCurrTxRate->upMcs1]) &&
+ (pCurrTxRate->upMcs1 != pCurrTxRate->ItemNo)))
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: ###################################################"
+ "#######################\n",
+ __FUNCTION__));
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: [2x2 peer device (Adhoc, DLS or AP)], Before - "
+ "pEntry->AGSCtrl.MCSGroup = %d, TxQuality1[%d] = %d, "
+ "TxQuality0[%d] = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup,
+ pCurrTxRate->upMcs2,
+ pEntry->TxQuality[pCurrTxRate->upMcs2],
+ pCurrTxRate->upMcs1,
+ pEntry->TxQuality[pCurrTxRate->upMcs1]));
+ }
+ }
+ else
+ {
+ /* */
+ /* 1x1 peer device (Adhoc, DLS or AP) */
+ /* */
+ switch (pEntry->AGSCtrl.MCSGroup)
+ {
+ case 1:
+ case 0:
+ {
+ UpRateIdx = pCurrTxRate->upMcs1;
+ }
+ break;
+
+ default:
+ {
+ DBGPRINT_RAW(RT_DEBUG_ERROR,
+ ("%s: AGS: [1x1 peer device (Adhoc, DLS or AP)], "
+ "Incorrect MCS group, pEntry->AGSCtrl.MCSGroup = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup));
+ }
+ break;
+ }
+ }
+
+
+ /* */
+ /* The STA uses the best Tx rate at this moment. */
+ /* */
+ if (UpRateIdx == pEntry->CurrTxRateIndex)
+ {
+ /* current rate is the best one */
+ pEntry->AGSCtrl.MCSGroup = 0; /* Try to escape the local optima */
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> Current rate is the best one!\n"));
+ break;
+ }
+
+ if ((pEntry->TxQuality[UpRateIdx] > 0) &&
+ (pEntry->AGSCtrl.MCSGroup > 0))
+ {
+ /*
+ Quality of up rate is bad try to use lower group.
+ So continue to get the up rate index.
+ */
+ pEntry->AGSCtrl.MCSGroup--; /* Try to use the MCS of the lower MCS group */
+ }
+ else
+ {
+ break;
+ }
+ } while (1);
+
+
+ DownRateIdx = pCurrTxRate->downMcs;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> UpRateIdx = %d, DownRateIdx = %d\n",
+ UpRateIdx, DownRateIdx));
+
+#ifdef DOT11_N_SUPPORT
+ if ((pAGSStatisticsInfo->RSSI > -65) &&
+ (pCurrTxRate->Mode >= MODE_HTMIX))
+ {
+ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
+ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {
+ TrainUp = pCurrTxRate->TrainUp;
+ TrainDown = pCurrTxRate->TrainDown;
+ }
+
+ /* */
+ /* Keep the TxRateChangeAction status */
+ /* */
+ pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction;
+
+
+
+ /* */
+ /* MCS selection based on the RSSI information when the Tx samples are fewer than 15. */
+ /* */
+ if (pAGSStatisticsInfo->AccuTxTotalCnt <= 15)
+ {
+ CHAR idx = 0;
+ UCHAR TxRateIdx;
+ UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0;
+ UCHAR MCS8 = 0, MCS9 = 0, MCS10 = 0, MCS11 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
+ UCHAR MCS16 = 0, MCS17 = 0, MCS18 = 0, MCS19 = 0, MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0;
+
+ /* */
+ /* Check the existence and index of each needed MCS */
+ /* */
+ /* for 3*3, maximum is 0x19 columns */
+ while (idx < pTable[0])
+ {
+ pCurrTxRate = (PRTMP_TX_RATE_SWITCH_AGS)(&pTable[(idx + 1) * SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+
+ if (pCurrTxRate->CurrMCS == MCS_0)
+ {
+ MCS0 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_1)
+ {
+ MCS1 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_2)
+ {
+ MCS2 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_3)
+ {
+ MCS3 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_4)
+ {
+ MCS4 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_5)
+ {
+ MCS5 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_6)
+ {
+ MCS6 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_7)
+ {
+ MCS7 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_8)
+ {
+ MCS8 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_9)
+ {
+ MCS9 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_10)
+ {
+ MCS10 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_11)
+ {
+ MCS11 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_12)
+ {
+ MCS12 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_13)
+ {
+ MCS13 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_14)
+ {
+ MCS14 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_15)
+ {
+ MCS15 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_16)
+ {
+ MCS16 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_17)
+ {
+ MCS17 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_18)
+ {
+ MCS18 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_19)
+ {
+ MCS19 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_20)
+ {
+ MCS20 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_21)
+ {
+ MCS21 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_22)
+ {
+ MCS22 = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_23)
+ {
+ MCS23 = idx;
+ }
+
+ idx++;
+ }
+
+ RssiOffset = 0;
+
+ if (InitTxRateIdx == AGS3x3HTRateTable[1])
+ {
+ /* */
+ /* 3x3 peer device (Adhoc, DLS or AP) */
+ /* */
+ if (MCS23 && (pAGSStatisticsInfo->RSSI > (-67 + RssiOffset)))
+ {
+ TxRateIdx = MCS23;
+ }
+ else if (MCS22 && (pAGSStatisticsInfo->RSSI > (-69 + RssiOffset)))
+ {
+ TxRateIdx = MCS22;
+ }
+ else if (MCS21 && (pAGSStatisticsInfo->RSSI > (-72 + RssiOffset)))
+ {
+ TxRateIdx = MCS21;
+ }
+ else if (MCS20 && (pAGSStatisticsInfo->RSSI > (-74 + RssiOffset)))
+ {
+ TxRateIdx = MCS20;
+ }
+ else if (MCS19 && (pAGSStatisticsInfo->RSSI > (-78 + RssiOffset)))
+ {
+ TxRateIdx = MCS19;
+ }
+ else if (MCS18 && (pAGSStatisticsInfo->RSSI > (-80 + RssiOffset)))
+ {
+ TxRateIdx = MCS18;
+ }
+ else if (MCS17 && (pAGSStatisticsInfo->RSSI > (-85 + RssiOffset)))
+ {
+ TxRateIdx = MCS17;
+ }
+ else
+ {
+ TxRateIdx = MCS16;
+ }
+
+ pEntry->AGSCtrl.MCSGroup = 3;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> Group3 RSSI = %d, TxRateIdx = %d\n",
+ pAGSStatisticsInfo->RSSI, TxRateIdx));
+ }
+ else if (InitTxRateIdx == AGS2x2HTRateTable[1])
+ {
+ /* */
+ /* 2x2 peer device (Adhoc, DLS or AP) */
+ /* */
+ if (MCS15 && (pAGSStatisticsInfo->RSSI > (-69 + RssiOffset)))
+ {
+ TxRateIdx = MCS15;
+ }
+ else if (MCS14 && (pAGSStatisticsInfo->RSSI > (-71 + RssiOffset)))
+ {
+ TxRateIdx = MCS14;
+ }
+ else if (MCS13 && (pAGSStatisticsInfo->RSSI > (-74 + RssiOffset)))
+ {
+ TxRateIdx = MCS13;
+ }
+ else if (MCS12 && (pAGSStatisticsInfo->RSSI > (-76 + RssiOffset)))
+ {
+ TxRateIdx = MCS12;
+ }
+ else if (MCS11 && (pAGSStatisticsInfo->RSSI > (-80 + RssiOffset)))
+ {
+ TxRateIdx = MCS11;
+ }
+ else if (MCS10 && (pAGSStatisticsInfo->RSSI > (-82 + RssiOffset)))
+ {
+ TxRateIdx = MCS10;
+ }
+ else if (MCS9 && (pAGSStatisticsInfo->RSSI > (-87 + RssiOffset)))
+ {
+ TxRateIdx = MCS9;
+ }
+ else
+ {
+ TxRateIdx = MCS8;
+ }
+
+ pEntry->AGSCtrl.MCSGroup = 2;
+ }
+ else
+ {
+ /* */
+ /* 1x1 peer device (Adhoc, DLS or AP) */
+ /* */
+ if (MCS7 && (pAGSStatisticsInfo->RSSI > (-71 + RssiOffset)))
+ {
+ TxRateIdx = MCS7;
+ }
+ else if (MCS6 && (pAGSStatisticsInfo->RSSI > (-73 + RssiOffset)))
+ {
+ TxRateIdx = MCS6;
+ }
+ else if (MCS5 && (pAGSStatisticsInfo->RSSI > (-76 + RssiOffset)))
+ {
+ TxRateIdx = MCS5;
+ }
+ else if (MCS4 && (pAGSStatisticsInfo->RSSI > (-78 + RssiOffset)))
+ {
+ TxRateIdx = MCS4;
+ }
+ else if (MCS3 && (pAGSStatisticsInfo->RSSI > (-82 + RssiOffset)))
+ {
+ TxRateIdx = MCS3;
+ }
+ else if (MCS2 && (pAGSStatisticsInfo->RSSI > (-84 + RssiOffset)))
+ {
+ TxRateIdx = MCS2;
+ }
+ else if (MCS1 && (pAGSStatisticsInfo->RSSI > (-89 + RssiOffset)))
+ {
+ TxRateIdx = MCS1;
+ }
+ else
+ {
+ TxRateIdx = MCS0;
+ }
+
+ pEntry->AGSCtrl.MCSGroup = 1;
+ }
+
+ pEntry->AGSCtrl.lastRateIdx = pEntry->CurrTxRateIndex;
+ pEntry->CurrTxRateIndex = TxRateIdx;
+
+ pNextTxRate = (PRTMP_TX_RATE_SWITCH)(&pTable[(pEntry->CurrTxRateIndex + 1) * SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+ MlmeSetTxRate(pAd, pEntry, pNextTxRate);
+
+ RTMPZeroMemory(pEntry->TxQuality, (sizeof(USHORT) * (MAX_TX_RATE_INDEX+1)));
+ RTMPZeroMemory(pEntry->PER, (sizeof(UCHAR) * (MAX_TX_RATE_INDEX+1)));
+
+ pEntry->fLastSecAccordingRSSI = TRUE;
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+ return;
+ }
+
+
+ /* */
+ /* The MCS selection is based on the RSSI and skips the rate tuning this time. */
+ /* */
+ if (pEntry->fLastSecAccordingRSSI == TRUE)
+ {
+ pEntry->fLastSecAccordingRSSI = FALSE;
+ pEntry->LastSecTxRateChangeAction = 0;
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: The MCS selection is based on the RSSI, and skips "
+ "the rate tuning this time.\n",
+ __FUNCTION__));
+
+ return;
+ }
+
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: TrainUp:%d, TrainDown:%d\n",
+ __FUNCTION__, TrainUp, TrainDown));
+
+ do
+ {
+ BOOLEAN bTrainUpDown = FALSE;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: TxQuality[CurrRateIdx(%d)] = %d, UpPenalty:%d\n",
+ __FUNCTION__, CurrRateIdx,
+ pEntry->TxQuality[CurrRateIdx], pEntry->TxRateUpPenalty));
+
+ if (pAGSStatisticsInfo->TxErrorRatio >= TrainDown) /* Poor quality */
+ {
+ /* error ratio too high, do rate down */
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: (DOWN) TxErrorRatio >= TrainDown\n",__FUNCTION__));
+ bTrainUpDown = TRUE;
+ pEntry->TxQuality[CurrRateIdx] = AGS_TX_QUALITY_WORST_BOUND;
+ }
+ else if (pAGSStatisticsInfo->TxErrorRatio <= TrainUp) /* Good quality */
+ {
+ /* error ratio low, maybe rate up */
+ bTrainUpDown = TRUE;
+ bUpgradeQuality = TRUE;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("%s: AGS: (UP) pEntry->TxQuality[CurrRateIdx] = %d, "
+ "pEntry->TxRateUpPenalty = %d\n",
+ __FUNCTION__,
+ pEntry->TxQuality[CurrRateIdx],
+ pEntry->TxRateUpPenalty));
+
+ if (pEntry->TxQuality[CurrRateIdx])
+ {
+ /* Good quality in the current Tx rate */
+ pEntry->TxQuality[CurrRateIdx]--;
+ }
+
+ if (pEntry->TxRateUpPenalty) /* no use for the parameter */
+ {
+ pEntry->TxRateUpPenalty--;
+ }
+ else
+ {
+ if (pEntry->TxQuality[pCurrTxRate->upMcs3] &&
+ (pCurrTxRate->upMcs3 != CurrRateIdx))
+ {
+ /* hope do rate up next time for the MCS */
+ pEntry->TxQuality[pCurrTxRate->upMcs3]--;
+ }
+
+ if (pEntry->TxQuality[pCurrTxRate->upMcs2] &&
+ (pCurrTxRate->upMcs2 != CurrRateIdx))
+ {
+ /* hope do rate up next time for the MCS */
+ pEntry->TxQuality[pCurrTxRate->upMcs2]--;
+ }
+
+ if (pEntry->TxQuality[pCurrTxRate->upMcs1] &&
+ (pCurrTxRate->upMcs1 != CurrRateIdx))
+ {
+ /* hope do rate up next time for the MCS */
+ pEntry->TxQuality[pCurrTxRate->upMcs1]--;
+ }
+ }
+ }
+ else if (pEntry->AGSCtrl.MCSGroup > 0) /*even if TxErrorRatio > TrainUp */
+ {
+ /* not bad and not good */
+ if (UpRateIdx != 0)
+ {
+ bTrainUpDown = TRUE;
+
+ if (pEntry->TxQuality[CurrRateIdx])
+ {
+ /* Good quality in the current Tx rate */
+ pEntry->TxQuality[CurrRateIdx]--;
+ }
+
+ if (pEntry->TxQuality[UpRateIdx])
+ {
+ /* It may improve next train-up Tx rate's quality */
+ pEntry->TxQuality[UpRateIdx]--;
+ }
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("ags> not bad and not good\n"));
+ }
+ }
+
+ /* update error ratio for current MCS */
+ pEntry->PER[CurrRateIdx] = (UCHAR)(pAGSStatisticsInfo->TxErrorRatio);
+
+ /* */
+ /* Update the current Tx rate */
+ /* */
+ if (bTrainUpDown)
+ {
+ /* need to rate up or down */
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: AGS: bTrainUpDown = %d, CurrRateIdx = %d, DownRateIdx = %d, UpRateIdx = %d, pEntry->TxQuality[CurrRateIdx] = %d, pEntry->TxQuality[UpRateIdx] = %d\n",
+ __FUNCTION__,
+ bTrainUpDown,
+ CurrRateIdx,
+ DownRateIdx,
+ UpRateIdx,
+ pEntry->TxQuality[CurrRateIdx],
+ pEntry->TxQuality[UpRateIdx]));
+
+ /* Downgrade Tx rate */
+ if ((CurrRateIdx != DownRateIdx) &&
+ (pEntry->TxQuality[CurrRateIdx] >= AGS_TX_QUALITY_WORST_BOUND))
+ {
+ pEntry->CurrTxRateIndex = DownRateIdx;
+ pEntry->LastSecTxRateChangeAction = 2; /* Tx rate down */
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("ags> rate down!\n"));
+ }
+ else if ((CurrRateIdx != UpRateIdx) &&
+ (pEntry->TxQuality[UpRateIdx] <= 0)) /* Upgrade Tx rate */
+ {
+ pEntry->CurrTxRateIndex = UpRateIdx;
+ pEntry->LastSecTxRateChangeAction = 1; /* Tx rate up */
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("ags> rate up!\n"));
+ }
+ }
+ } while (FALSE);
+
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: AGS: pEntry->CurrTxRateIndex = %d, CurrRateIdx = %d, pEntry->LastSecTxRateChangeAction = %d\n",
+ __FUNCTION__,
+ pEntry->CurrTxRateIndex,
+ CurrRateIdx,
+ pEntry->LastSecTxRateChangeAction));
+
+ /* rate up/down post handle */
+ /* Tx rate up */
+ if ((pEntry->CurrTxRateIndex != CurrRateIdx) &&
+ (pEntry->LastSecTxRateChangeAction == 1))
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: AGS: ++TX rate from %d to %d\n",
+ __FUNCTION__,
+ CurrRateIdx,
+ pEntry->CurrTxRateIndex));
+
+ pEntry->TxRateUpPenalty = 0;
+ pEntry->LastSecTxRateChangeAction = 1; /* Tx rate up */
+ RTMPZeroMemory(pEntry->PER, sizeof(UCHAR) * (MAX_TX_RATE_INDEX+1));
+ pEntry->AGSCtrl.lastRateIdx = CurrRateIdx;
+
+ /* */
+ /* Tx rate fast train up */
+ /* */
+ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning)
+ {
+ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, DEF_QUICK_RA_TIME_INTERVAL);
+
+ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE;
+ }
+
+ bTxRateChanged = TRUE;
+ }
+ else if ((pEntry->CurrTxRateIndex != CurrRateIdx) &&
+ (pEntry->LastSecTxRateChangeAction == 2)) /* Tx rate down */
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: AGS: --TX rate from %d to %d\n",
+ __FUNCTION__,
+ CurrRateIdx,
+ pEntry->CurrTxRateIndex));
+
+ pEntry->TxRateUpPenalty = 0; /* No penalty */
+ pEntry->LastSecTxRateChangeAction = 2; /* Tx rate down */
+ pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
+ pEntry->PER[pEntry->CurrTxRateIndex] = 0;
+ pEntry->AGSCtrl.lastRateIdx = CurrRateIdx;
+
+ /* Tx rate fast train down */
+ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning)
+ {
+ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, DEF_QUICK_RA_TIME_INTERVAL);
+
+ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE;
+ }
+
+ bTxRateChanged = TRUE;
+ }
+ else /* Tx rate remains unchanged. */
+ {
+ pEntry->LastSecTxRateChangeAction = 0; /* Tx rate remains unchanged. */
+ bTxRateChanged = FALSE;
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("ags> no rate up/down!\n"));
+ }
+
+ pEntry->LastTxOkCount = pAGSStatisticsInfo->TxSuccess;
+
+ /* set new tx rate */
+ pNextTxRate = (PRTMP_TX_RATE_SWITCH)\
+ (&pTable[(pEntry->CurrTxRateIndex + 1) *
+ SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+
+ if ((bTxRateChanged == TRUE) && (pNextTxRate != NULL))
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> set new rate MCS = %d!\n", pEntry->CurrTxRateIndex));
+ MlmeSetTxRate(pAd, pEntry, pNextTxRate);
+ }
+
+ /* RDG threshold control for the infrastructure mode only */
+/* if (INFRA_ON(pAd) && (pAd->OpMode == OPMODE_STA) && (!DLS_ON(pAd)) && (!TDLS_ON(pAd))) */
+ if (INFRA_ON(pAd))
+ {
+ if ((pAd->CommonCfg.bRdg == TRUE) &&
+ CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID],
+ fCLIENT_STATUS_RDG_CAPABLE)) /* RDG capable */
+ {
+ TXOP_THRESHOLD_CFG_STRUC TxopThCfg = {{0}};
+ TX_LINK_CFG_STRUC TxLinkCfg = {{0}};
+
+ if ((pAd->RalinkCounters.OneSecReceivedByteCount > (pAd->RalinkCounters.OneSecTransmittedByteCount * 5)) &&
+ (pNextTxRate->CurrMCS != MCS_23) &&
+ ((pAd->RalinkCounters.OneSecReceivedByteCount + pAd->RalinkCounters.OneSecTransmittedByteCount) >= (50 * 1024)))
+ {
+ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
+ TxLinkCfg.field.TxRDGEn = 0;
+ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
+
+ RTMP_IO_READ32(pAd, TXOP_THRES_CFG, &TxopThCfg.word);
+ TxopThCfg.field.RDG_IN_THRES = 0xFF; /* Similar to diable Rx RDG */
+ TxopThCfg.field.RDG_OUT_THRES = 0x00;
+ RTMP_IO_WRITE32(pAd, TXOP_THRES_CFG, TxopThCfg.word);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AGS: %s: RDG_IN_THRES = 0xFF\n", __FUNCTION__));
+ }
+ else
+ {
+ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
+ TxLinkCfg.field.TxRDGEn = 1;
+ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
+
+ RTMP_IO_READ32(pAd, TXOP_THRES_CFG, &TxopThCfg.word);
+ TxopThCfg.field.RDG_IN_THRES = 0x00;
+ TxopThCfg.field.RDG_OUT_THRES = 0x00;
+ RTMP_IO_WRITE32(pAd, TXOP_THRES_CFG, TxopThCfg.word);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AGS: %s: RDG_IN_THRES = 0x00\n", __FUNCTION__));
+ }
+ }
+ }
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AGS: <--- %s\n", __FUNCTION__));
+}
+
+/*
+ Auto Tx rate faster train up/down for AGS (Adaptive Group Switching)
+
+ Parameters
+ pAd: The adapter data structure
+ pEntry: Pointer to a caller-supplied variable in which points to a MAC table entry
+ pTable: Pointer to a caller-supplied variable in wich points to a Tx rate switching table
+ TableSize: The size, in bytes, of the specified Tx rate switching table
+ pAGSStatisticsInfo: Pointer to a caller-supplied variable in which points to the statistics information
+
+ Return Value:
+ None
+*/
+VOID StaQuickResponeForRateUpExecAGS(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PUCHAR pTable,
+ IN UCHAR TableSize,
+ IN PAGS_STATISTICS_INFO pAGSStatisticsInfo,
+ IN UCHAR InitTxRateIdx)
+{
+ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
+ BOOLEAN bTxRateChanged = TRUE;
+ PRTMP_TX_RATE_SWITCH_AGS pCurrTxRate = NULL;
+ PRTMP_TX_RATE_SWITCH pNextTxRate = NULL;
+ UCHAR TrainDown = 0, TrainUp = 0;
+ CHAR ratio = 0;
+ ULONG OneSecTxNoRetryOKRationCount = 0;
+
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("QuickAGS: ---> %s\n", __FUNCTION__));
+
+ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;
+
+ DBGPRINT(RT_DEBUG_TRACE,
+ ("%s: QuickAGS: AccuTxTotalCnt = %lu, TxSuccess = %lu, "
+ "TxRetransmit = %lu, TxFailCount = %lu, TxErrorRatio = %lu\n",
+ __FUNCTION__,
+ pAGSStatisticsInfo->AccuTxTotalCnt,
+ pAGSStatisticsInfo->TxSuccess,
+ pAGSStatisticsInfo->TxRetransmit,
+ pAGSStatisticsInfo->TxFailCount,
+ pAGSStatisticsInfo->TxErrorRatio));
+
+ CurrRateIdx = pEntry->CurrTxRateIndex;
+
+ if (CurrRateIdx >= TableSize)
+ {
+ CurrRateIdx = TableSize - 1;
+ }
+
+ UpRateIdx = DownRateIdx = pEntry->AGSCtrl.lastRateIdx;
+
+ pCurrTxRate = (PRTMP_TX_RATE_SWITCH_AGS)(&pTable[(CurrRateIdx + 1) *
+ SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+
+ if ((pAGSStatisticsInfo->RSSI > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
+ {
+ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
+ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
+ }
+ else
+ {
+ TrainUp = pCurrTxRate->TrainUp;
+ TrainDown = pCurrTxRate->TrainDown;
+ }
+
+ /* MCS selection based on the RSSI information when the Tx samples are fewer than 15. */
+ if (pAGSStatisticsInfo->AccuTxTotalCnt <= 15)
+ {
+ RTMPZeroMemory(pEntry->TxQuality, sizeof(USHORT) * (MAX_TX_RATE_INDEX+1));
+ RTMPZeroMemory(pEntry->PER, sizeof(UCHAR) * (MAX_TX_RATE_INDEX+1));
+
+ if ((pEntry->LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx))
+ {
+ pEntry->CurrTxRateIndex = DownRateIdx;
+ pEntry->TxQuality[CurrRateIdx] = AGS_TX_QUALITY_WORST_BOUND;
+ }
+ else if ((pEntry->LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx))
+ {
+ pEntry->CurrTxRateIndex = UpRateIdx;
+ }
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: AccuTxTotalCnt <= 15, train back to original rate\n",
+ __FUNCTION__));
+
+ return;
+ }
+
+ do
+ {
+ if (pEntry->LastTimeTxRateChangeAction == 0)
+ {
+ ratio = 5;
+ }
+ else
+ {
+ ratio = 4;
+ }
+
+ if (pAGSStatisticsInfo->TxErrorRatio >= TrainDown) /* Poor quality */
+ {
+ pEntry->TxQuality[CurrRateIdx] = AGS_TX_QUALITY_WORST_BOUND;
+ }
+
+ pEntry->PER[CurrRateIdx] = (UCHAR)(pAGSStatisticsInfo->TxErrorRatio);
+
+ OneSecTxNoRetryOKRationCount = (pAGSStatisticsInfo->TxSuccess * ratio);
+
+ /* Tx rate down */
+ if ((pEntry->LastSecTxRateChangeAction == 1) &&
+ (CurrRateIdx != DownRateIdx))
+ {
+ if ((pEntry->LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) /* Poor quality */
+ {
+ pEntry->CurrTxRateIndex = DownRateIdx;
+ pEntry->TxQuality[CurrRateIdx] = AGS_TX_QUALITY_WORST_BOUND;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: (UP) bad Tx ok count (L:%lu, C:%lu)\n",
+ __FUNCTION__,
+ pEntry->LastTxOkCount,
+ OneSecTxNoRetryOKRationCount));
+ }
+ else /* Good quality */
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: (UP) keep rate-up (L:%lu, C:%lu)\n",
+ __FUNCTION__,
+ pEntry->LastTxOkCount,
+ OneSecTxNoRetryOKRationCount));
+
+ RTMPZeroMemory(pEntry->TxQuality, sizeof(USHORT) * (MAX_TX_RATE_INDEX+1));
+
+ if (pEntry->AGSCtrl.MCSGroup == 0)
+ {
+ if (InitTxRateIdx == AGS3x3HTRateTable[1])
+ {
+ /* */
+ /* 3x3 peer device (Adhoc, DLS or AP) */
+ /* */
+ pEntry->AGSCtrl.MCSGroup = 3;
+ }
+ else if (InitTxRateIdx == AGS2x2HTRateTable[1])
+ {
+ /* */
+ /* 2x2 peer device (Adhoc, DLS or AP) */
+ /* */
+ pEntry->AGSCtrl.MCSGroup = 2;
+ }
+ else
+ {
+ pEntry->AGSCtrl.MCSGroup = 1;
+ }
+ }
+ }
+ }
+ else if ((pEntry->LastSecTxRateChangeAction == 2) &&
+ (CurrRateIdx != UpRateIdx)) /* Tx rate up */
+ {
+ if ((pAGSStatisticsInfo->TxErrorRatio >= 50) ||
+ (pAGSStatisticsInfo->TxErrorRatio >= TrainDown)) /* Poor quality */
+ {
+ if (InitTxRateIdx == AGS3x3HTRateTable[1])
+ {
+ /* */
+ /* 3x3 peer device (Adhoc, DLS or AP) */
+ /* */
+ pEntry->AGSCtrl.MCSGroup = 3;
+ }
+ else if (InitTxRateIdx == AGS2x2HTRateTable[1])
+ {
+ /* */
+ /* 2x2 peer device (Adhoc, DLS or AP) */
+ /* */
+ pEntry->AGSCtrl.MCSGroup = 2;
+ }
+ else
+ {
+ pEntry->AGSCtrl.MCSGroup = 1;
+ }
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: (DOWN) direct train down (TxErrorRatio[%lu] >= TrainDown[%d])\n",
+ __FUNCTION__,
+ pAGSStatisticsInfo->TxErrorRatio,
+ TrainDown));
+ }
+ else if ((pEntry->LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
+ {
+ pEntry->CurrTxRateIndex = UpRateIdx;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: (DOWN) bad tx ok count (L:%lu, C:%lu)\n",
+ __FUNCTION__,
+ pEntry->LastTxOkCount,
+ OneSecTxNoRetryOKRationCount));
+ }
+ else
+ {
+ if (InitTxRateIdx == AGS3x3HTRateTable[1])
+ {
+ /* */
+ /* 3x3 peer device (Adhoc, DLS or AP) */
+ /* */
+ pEntry->AGSCtrl.MCSGroup = 3;
+ }
+ else if (InitTxRateIdx == AGS2x2HTRateTable[1])
+ {
+ /* */
+ /* 2x2 peer device (Adhoc, DLS or AP) */
+ /* */
+ pEntry->AGSCtrl.MCSGroup = 2;
+ }
+ else
+ {
+ pEntry->AGSCtrl.MCSGroup = 1;
+ }
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: (Down) keep rate-down (L:%lu, C:%lu)\n",
+ __FUNCTION__,
+ pEntry->LastTxOkCount,
+ OneSecTxNoRetryOKRationCount));
+ }
+ }
+ }while (FALSE);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> new group = %d\n", pEntry->AGSCtrl.MCSGroup));
+
+ /* */
+ /* Last action is rate-up */
+ /* */
+ if (pEntry->LastSecTxRateChangeAction == 1)
+ {
+ /* looking for the next group with valid MCS */
+ if ((pEntry->CurrTxRateIndex != CurrRateIdx) && (pEntry->AGSCtrl.MCSGroup > 0))
+ {
+ pEntry->AGSCtrl.MCSGroup--; /* Try to use the MCS of the lower MCS group */
+ pCurrTxRate = (PRTMP_TX_RATE_SWITCH_AGS)(&pTable[(DownRateIdx + 1) * SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+ }
+
+ /* UpRateIdx is for temp use in this section */
+ switch (pEntry->AGSCtrl.MCSGroup)
+ {
+ case 3:
+ {
+ UpRateIdx = pCurrTxRate->upMcs3;
+ }
+ break;
+
+ case 2:
+ {
+ UpRateIdx = pCurrTxRate->upMcs2;
+ }
+ break;
+
+ case 1:
+ {
+ UpRateIdx = pCurrTxRate->upMcs1;
+ }
+ break;
+
+ case 0:
+ {
+ UpRateIdx = CurrRateIdx;
+ }
+ break;
+
+ default:
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: Incorrect MCS group, pEntry->AGSCtrl.MCSGroup = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup));
+ }
+ break;
+ }
+
+ if (UpRateIdx == pEntry->CurrTxRateIndex)
+ {
+ pEntry->AGSCtrl.MCSGroup = 0; /* Try to escape the local optima */
+ }
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: next MCS group, pEntry->AGSCtrl.MCSGroup = %d\n",
+ __FUNCTION__,
+ pEntry->AGSCtrl.MCSGroup));
+
+ }
+
+ if ((pEntry->CurrTxRateIndex != CurrRateIdx) &&
+ (pEntry->LastSecTxRateChangeAction == 2)) /* Tx rate up */
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: ++TX rate from %d to %d\n",
+ __FUNCTION__,
+ CurrRateIdx,
+ pEntry->CurrTxRateIndex));
+
+ pEntry->TxRateUpPenalty = 0;
+ pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; /*restore the TxQuality from max to 0 */
+ RTMPZeroMemory(pEntry->PER, sizeof(UCHAR) * (MAX_TX_RATE_INDEX+1));
+ }
+ else if ((pEntry->CurrTxRateIndex != CurrRateIdx) &&
+ (pEntry->LastSecTxRateChangeAction == 1)) /* Tx rate down */
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: --TX rate from %d to %d\n",
+ __FUNCTION__,
+ CurrRateIdx,
+ pEntry->CurrTxRateIndex));
+
+ pEntry->TxRateUpPenalty = 0; /* No penalty */
+ pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
+ pEntry->PER[pEntry->CurrTxRateIndex] = 0;
+ }
+ else
+ {
+ bTxRateChanged = FALSE;
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s: QuickAGS: rate is not changed\n",
+ __FUNCTION__));
+ }
+
+ pNextTxRate = (PRTMP_TX_RATE_SWITCH)(&pTable[(pEntry->CurrTxRateIndex + 1) * SIZE_OF_AGS_RATE_TABLE_ENTRY]);
+ if ((bTxRateChanged == TRUE) && (pNextTxRate != NULL))
+ {
+ DBGPRINT_RAW(RT_DEBUG_TRACE,
+ ("ags> confirm current rate MCS = %d!\n", pEntry->CurrTxRateIndex));
+
+ MlmeSetTxRate(pAd, pEntry, pNextTxRate);
+ }
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("QuickAGS: <--- %s\n", __FUNCTION__));
+}
+
+
+
+#endif /* AGS_SUPPORT */
+
+/* End of ags.c */
diff --git a/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_grp.c b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_grp.c
new file mode 100644
index 0000000000..359f48fa4d
--- /dev/null
+++ b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_grp.c
@@ -0,0 +1,1621 @@
+/****************************************************************************
+ * Ralink Tech Inc.
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2010, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************/
+
+/****************************************************************************
+
+ Abstract:
+
+ All related Dynamic Rate Switch (AP/STA) function body.
+
+ History:
+
+***************************************************************************/
+
+#ifdef NEW_RATE_ADAPT_SUPPORT
+#include "rt_config.h"
+
+
+/*
+ MlmeSetMcsGroup - set initial mcsGroup based on supported MCSs
+ On exit pEntry->mcsGroup is set to the mcsGroup
+*/
+VOID MlmeSetMcsGroup(
+ IN PRTMP_ADAPTER pAd,
+ OUT PMAC_TABLE_ENTRY pEntry)
+{
+#ifdef DOT11N_SS3_SUPPORT
+ if ((pEntry->HTCapability.MCSSet[2] == 0xff) && (pAd->CommonCfg.TxStream == 3))
+ pEntry->mcsGroup = 3;
+ else
+#endif /* DOT11N_SS3_SUPPORT */
+ if ((pEntry->HTCapability.MCSSet[0] == 0xff) &&
+ (pEntry->HTCapability.MCSSet[1] == 0xff) &&
+ (pAd->CommonCfg.TxStream > 1) &&
+ ((pAd->CommonCfg.TxStream == 2) || (pEntry->HTCapability.MCSSet[2] == 0x0)))
+ pEntry->mcsGroup = 2;
+ else
+ pEntry->mcsGroup = 1;
+}
+
+
+/*
+ MlmeSelectUpRate - select UpRate based on MCS group
+ returns the UpRate index and updates the MCS group
+*/
+UCHAR MlmeSelectUpRate(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PRTMP_TX_RATE_SWITCH_3S pCurrTxRate)
+{
+ UCHAR UpRateIdx = 0;
+
+ while (1)
+ {
+ if ((pEntry->HTCapability.MCSSet[2] == 0xff) && (pAd->CommonCfg.TxStream == 3))
+ {
+ switch (pEntry->mcsGroup)
+ {
+ case 0:/* improvement: use round robin mcs when group == 0 */
+ UpRateIdx = pCurrTxRate->upMcs3;
+ if (UpRateIdx == pCurrTxRate->ItemNo)
+ {
+ UpRateIdx = pCurrTxRate->upMcs2;
+ if (UpRateIdx == pCurrTxRate->ItemNo)
+ UpRateIdx = pCurrTxRate->upMcs1;
+ }
+
+ if (MlmeGetTxQuality(pEntry, UpRateIdx) > MlmeGetTxQuality(pEntry, pCurrTxRate->upMcs2) &&
+ pCurrTxRate->upMcs2 != pCurrTxRate->ItemNo)
+ UpRateIdx = pCurrTxRate->upMcs2;
+
+ if (MlmeGetTxQuality(pEntry, UpRateIdx) > MlmeGetTxQuality(pEntry, pCurrTxRate->upMcs1) &&
+ pCurrTxRate->upMcs1 != pCurrTxRate->ItemNo)
+ UpRateIdx = pCurrTxRate->upMcs1;
+ break;
+ case 3:
+ UpRateIdx = pCurrTxRate->upMcs3;
+ break;
+ case 2:
+ UpRateIdx = pCurrTxRate->upMcs2;
+ break;
+ case 1:
+ UpRateIdx = pCurrTxRate->upMcs1;
+ break;
+ default:
+ DBGPRINT_RAW(RT_DEBUG_ERROR, ("wrong mcsGroup value\n"));
+ break;
+ }
+
+ }
+ else if ((pEntry->HTCapability.MCSSet[0] == 0xff) &&
+ (pEntry->HTCapability.MCSSet[1] == 0xff) &&
+ (pAd->CommonCfg.TxStream > 1) &&
+ ((pAd->CommonCfg.TxStream == 2) || (pEntry->HTCapability.MCSSet[2] == 0x0)))
+ {
+ switch (pEntry->mcsGroup)
+ {
+ case 0:
+ UpRateIdx = pCurrTxRate->upMcs2;
+ if (UpRateIdx == pCurrTxRate->ItemNo)
+ UpRateIdx = pCurrTxRate->upMcs1;
+
+ if (MlmeGetTxQuality(pEntry, UpRateIdx) > MlmeGetTxQuality(pEntry, pCurrTxRate->upMcs1) &&
+ pCurrTxRate->upMcs1 != pCurrTxRate->ItemNo)
+ UpRateIdx = pCurrTxRate->upMcs1;
+ break;
+ case 2:
+ UpRateIdx = pCurrTxRate->upMcs2;
+ break;
+ case 1:
+ UpRateIdx = pCurrTxRate->upMcs1;
+ break;
+ default:
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("wrong mcsGroup value %d\n", pEntry->mcsGroup));
+ break;
+ }
+
+ }
+ else
+ {
+ switch (pEntry->mcsGroup)
+ {
+ case 1:
+ case 0:
+ UpRateIdx = pCurrTxRate->upMcs1;
+ break;
+ default:
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("wrong mcsGroup value %d\n", pEntry->mcsGroup));
+ break;
+ }
+ }
+
+ /* If going up from CCK to MCS32 make sure it's allowed */
+ if (PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, UpRateIdx)->CurrMCS == 32)
+ {
+ /* If not allowed then skip over it */
+ BOOLEAN mcs32Supported = 0;
+ BOOLEAN mcs0Fallback = 0;
+
+ if ((pEntry->HTCapability.MCSSet[4] & 0x1)
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_ENABLE_HT_DUP)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ mcs32Supported = 1;
+
+#ifdef DBG_CTRL_SUPPORT
+ if ((pAd->CommonCfg.DebugFlags & DBF_DISABLE_20MHZ_MCS0)==0)
+ mcs0Fallback = 1;
+#endif /* DBG_CTRL_SUPPORT */
+
+ if (pEntry->MaxHTPhyMode.field.BW!=BW_40 || pAd->CommonCfg.BBPCurrentBW!=BW_40 ||
+ (!mcs32Supported && !mcs0Fallback)
+ )
+ {
+ UpRateIdx = PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, UpRateIdx)->upMcs1;
+ pEntry->mcsGroup = 1;
+ break;
+ }
+ }
+
+ /* If ShortGI and not allowed then mark it as bad. We'll try another group below */
+ if (PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, UpRateIdx)->ShortGI &&
+ !pEntry->MaxHTPhyMode.field.ShortGI)
+ {
+ MlmeSetTxQuality(pEntry, UpRateIdx, DRS_TX_QUALITY_WORST_BOUND*2);
+ }
+
+ /* If we reached the end of the group then select the best next time */
+ if (UpRateIdx == pEntry->CurrTxRateIndex)
+ {
+ pEntry->mcsGroup = 0;
+ break;
+ }
+
+ /* If the current group has bad TxQuality then try another group */
+ if ((MlmeGetTxQuality(pEntry, UpRateIdx) > 0) && (pEntry->mcsGroup > 0))
+ pEntry->mcsGroup--;
+ else
+ break;
+ }
+
+ return UpRateIdx;
+}
+
+/*
+ MlmeSelectDownRate - select DownRate.
+ pEntry->pTable is assumed to be a pointer to an adaptive rate table with mcsGroup values
+ CurrRateIdx - current rate index
+ returns the DownRate index. Down Rate = CurrRateIdx if there is no valid Down Rate
+*/
+UCHAR MlmeSelectDownRate(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR CurrRateIdx)
+{
+ UCHAR DownRateIdx = PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, CurrRateIdx)->downMcs;
+ PRTMP_TX_RATE_SWITCH_3S pDownRate;
+
+ /* Loop until a valid down rate is found */
+ while (1) {
+ pDownRate = PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, DownRateIdx);
+
+ /* Break out of loop if rate is valid */
+ if (pDownRate->Mode==MODE_CCK)
+ {
+ /* CCK is valid only if in G band and if not disabled */
+ if ((pAd->LatchRfRegs.Channel<=14
+#ifdef DBG_CTRL_SUPPORT
+ || (pAd->CommonCfg.DebugFlags & DBF_ENABLE_CCK_5G)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+#ifdef DBG_CTRL_SUPPORT
+ && ((pAd->CommonCfg.DebugFlags & DBF_DISABLE_CCK)==0)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ break;
+ }
+ else if (pDownRate->CurrMCS == MCS_32)
+ {
+ /* If 20MHz MCS0 fallback enabled and in 40MHz then MCS32 is valid and will be mapped to 20MHz MCS0 */
+ if (pEntry->MaxHTPhyMode.field.BW==BW_40 &&
+ pAd->CommonCfg.BBPCurrentBW==BW_40
+#ifdef DBG_CTRL_SUPPORT
+ && ((pAd->CommonCfg.DebugFlags & DBF_DISABLE_20MHZ_MCS0)==0)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ break;
+
+ /* MCS32 is valid if enabled and client supports it */
+ if (pEntry->MaxHTPhyMode.field.BW==BW_40 &&
+ pAd->CommonCfg.BBPCurrentBW==BW_40 &&
+ (pEntry->HTCapability.MCSSet[4] & 0x1)
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_ENABLE_HT_DUP)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ break;
+ }
+ else
+ break; /* All other rates are valid */
+
+ /* Return original rate if we reached the end without finding a valid rate */
+ if (DownRateIdx == pDownRate->downMcs)
+ return CurrRateIdx;
+
+ /* Otherwise try the next lower rate */
+ DownRateIdx = pDownRate->downMcs;
+ }
+
+ return DownRateIdx;
+}
+
+/*
+ MlmeGetSupportedMcsAdapt - fills in the table of supported MCSs
+ pAd - pointer to adapter
+ pEntry - MAC Table entry. pEntry->pTable is a rate table with mcsGroup values
+ mcs23GI - the MCS23 entry will have this guard interval
+ mcs - table of MCS index into the Rate Table. -1 => not supported
+*/
+VOID MlmeGetSupportedMcsAdapt(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR mcs23GI,
+ OUT CHAR mcs[])
+{
+ CHAR idx;
+ PRTMP_TX_RATE_SWITCH_3S pCurrTxRate;
+ UCHAR *pTable = pEntry->pTable;
+
+ for (idx=0; idx<24; idx++)
+ mcs[idx] = -1;
+
+ /* check the existence and index of each needed MCS */
+ for (idx=0; idx<RATE_TABLE_SIZE(pTable); idx++)
+ {
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, idx);
+
+ if ((pCurrTxRate->CurrMCS>=8 && pAd->CommonCfg.TxStream<2) ||
+ (pCurrTxRate->CurrMCS>=16 && pAd->CommonCfg.TxStream<3))
+ continue;
+
+ /* Rate Table may contain CCK and MCS rates. Give HT/Legacy priority over CCK */
+ if (pCurrTxRate->CurrMCS==MCS_0 && (mcs[0]==-1 || pCurrTxRate->Mode!=MODE_CCK))
+ {
+ mcs[0] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS==MCS_1 && (mcs[1]==-1 || pCurrTxRate->Mode!=MODE_CCK))
+ {
+ mcs[1] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS==MCS_2 && (mcs[2]==-1 || pCurrTxRate->Mode!=MODE_CCK))
+ {
+ mcs[2] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_3)
+ {
+ mcs[3] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_4)
+ {
+ mcs[4] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_5)
+ {
+ mcs[5] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_6)
+ {
+ mcs[6] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[7] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_8)
+ {
+ mcs[8] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_9)
+ {
+ mcs[9] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_10)
+ {
+ mcs[10] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_11)
+ {
+ mcs[11] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_12)
+ {
+ mcs[12] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_13)
+ {
+ mcs[13] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_14) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[14] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[15] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_16)
+ {
+ mcs[16] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_17)
+ {
+ mcs[17] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_18)
+ {
+ mcs[18] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_19)
+ {
+ mcs[19] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_20)
+ {
+ mcs[20] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_21) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[21] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_22) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[22] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_23) && (pCurrTxRate->ShortGI == mcs23GI))
+ {
+ mcs[23] = idx;
+ }
+ }
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug Option: Disable highest MCSs when picking initial MCS based on RSSI */
+ if (pAd->CommonCfg.DebugFlags & DBF_INIT_MCS_DIS1)
+ mcs[23] = mcs[15] = mcs[7] = mcs[22] = mcs[14] = mcs[6] = 0;
+#endif /* DBG_CTRL_SUPPORT */
+
+}
+
+
+/*
+ MlmeSelectTxRateAdapt - select the MCS based on the RSSI and the available MCSs
+ pAd - pointer to adapter
+ pEntry - pointer to MAC table entry
+ mcs - table of MCS index into the Rate Table. -1 => not supported
+ Rssi - the Rssi value
+ RssiOffset - offset to apply to the Rssi
+*/
+UCHAR MlmeSelectTxRateAdapt(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN CHAR mcs[],
+ IN CHAR Rssi,
+ IN CHAR RssiOffset)
+{
+ UCHAR TxRateIdx = 0;
+ UCHAR *pTable = pEntry->pTable;
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug option: Add 6 dB of margin */
+ if (pAd->CommonCfg.DebugFlags & DBF_INIT_MCS_MARGIN)
+ RssiOffset += 6;
+#endif /* DBG_CTRL_SUPPORT */
+
+#ifdef DOT11_N_SUPPORT
+ if (ADAPT_RATE_TABLE(pTable) ||
+ (pTable == RateSwitchTable11BGN3S) ||
+ (pTable == RateSwitchTable11BGN3SForABand))
+ {/* N mode with 3 stream */
+ if ((pEntry->HTCapability.MCSSet[2] == 0xff) && (pAd->CommonCfg.TxStream == 3))
+ {
+ if (mcs[23]>=0 && (Rssi > (-72+RssiOffset)))
+ TxRateIdx = mcs[23];
+ else if (mcs[22]>=0 && (Rssi > (-74+RssiOffset)))
+ TxRateIdx = mcs[22];
+ else if (mcs[21]>=0 && (Rssi > (-77+RssiOffset)))
+ TxRateIdx = mcs[21];
+ else if (mcs[20]>=0 && (Rssi > (-79+RssiOffset)))
+ TxRateIdx = mcs[20];
+ else if (mcs[11]>=0 && (Rssi > (-81+RssiOffset)))
+ TxRateIdx = mcs[11];
+ else if (mcs[10]>=0 && (Rssi > (-83+RssiOffset)))
+ TxRateIdx = mcs[10];
+ else if (mcs[2]>=0 && (Rssi > (-86+RssiOffset)))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > (-88+RssiOffset)))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+
+ pEntry->mcsGroup = 3;
+ }
+ else if ((pEntry->HTCapability.MCSSet[0] == 0xff) &&
+ (pEntry->HTCapability.MCSSet[1] == 0xff) &&
+ (pAd->CommonCfg.TxStream > 1) &&
+ ((pAd->CommonCfg.TxStream == 2) || (pEntry->HTCapability.MCSSet[2] == 0x0)))
+ {
+ if (mcs[15]>=0 && (Rssi > (-72+RssiOffset)))
+ TxRateIdx = mcs[15];
+ else if (mcs[14]>=0 && (Rssi > (-74+RssiOffset)))
+ TxRateIdx = mcs[14];
+ else if (mcs[13]>=0 && (Rssi > (-77+RssiOffset)))
+ TxRateIdx = mcs[13];
+ else if (mcs[12]>=0 && (Rssi > (-79+RssiOffset)))
+ TxRateIdx = mcs[12];
+ else if (mcs[11]>=0 && (Rssi > (-81+RssiOffset)))
+ TxRateIdx = mcs[11];
+ else if (mcs[10]>=0 && (Rssi > (-83+RssiOffset)))
+ TxRateIdx = mcs[10];
+ else if (mcs[2]>=0 && (Rssi > (-86+RssiOffset)))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > (-88+RssiOffset)))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+
+ pEntry->mcsGroup = 2;
+ }
+ else
+ {
+ if (mcs[7]>=0 && (Rssi > (-72+RssiOffset)))
+ TxRateIdx = mcs[7];
+ else if (mcs[6]>=0 && (Rssi > (-74+RssiOffset)))
+ TxRateIdx = mcs[6];
+ else if (mcs[5]>=0 && (Rssi > (-77+RssiOffset)))
+ TxRateIdx = mcs[5];
+ else if (mcs[4]>=0 && (Rssi > (-79+RssiOffset)))
+ TxRateIdx = mcs[4];
+ else if (mcs[3]>=0 && (Rssi > (-81+RssiOffset)))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi > (-83+RssiOffset)))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > (-86+RssiOffset)))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+
+ pEntry->mcsGroup = 1;
+ }
+ }
+ else if ((pTable == RateSwitchTable11BGN2S) ||
+ (pTable == RateSwitchTable11BGN2SForABand) ||
+ (pTable == RateSwitchTable11N2S) ||
+ (pTable == RateSwitchTable11N2SForABand))
+ {/* N mode with 2 stream */
+ if (mcs[15]>=0 && (Rssi >= (-70+RssiOffset)))
+ TxRateIdx = mcs[15];
+ else if (mcs[14]>=0 && (Rssi >= (-72+RssiOffset)))
+ TxRateIdx = mcs[14];
+ else if (mcs[13]>=0 && (Rssi >= (-76+RssiOffset)))
+ TxRateIdx = mcs[13];
+ else if (mcs[12]>=0 && (Rssi >= (-78+RssiOffset)))
+ TxRateIdx = mcs[12];
+ else if (mcs[4]>=0 && (Rssi >= (-82+RssiOffset)))
+ TxRateIdx = mcs[4];
+ else if (mcs[3]>=0 && (Rssi >= (-84+RssiOffset)))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi >= (-86+RssiOffset)))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi >= (-88+RssiOffset)))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+ else if ((pTable == RateSwitchTable11BGN1S) ||
+ (pTable == RateSwitchTable11N1S) ||
+ (pTable == RateSwitchTable11N1SForABand))
+ {/* N mode with 1 stream */
+ if (mcs[7]>=0 && (Rssi > (-72+RssiOffset)))
+ TxRateIdx = mcs[7];
+ else if (mcs[6]>=0 && (Rssi > (-74+RssiOffset)))
+ TxRateIdx = mcs[6];
+ else if (mcs[5]>=0 && (Rssi > (-77+RssiOffset)))
+ TxRateIdx = mcs[5];
+ else if (mcs[4]>=0 && (Rssi > (-79+RssiOffset)))
+ TxRateIdx = mcs[4];
+ else if (mcs[3]>=0 && (Rssi > (-81+RssiOffset)))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi > (-83+RssiOffset)))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > (-86+RssiOffset)))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {/* Legacy mode */
+ if (mcs[7]>=0 && (Rssi > -70))
+ TxRateIdx = mcs[7];
+ else if (mcs[6]>=0 && (Rssi > -74))
+ TxRateIdx = mcs[6];
+ else if (mcs[5]>=0 && (Rssi > -78))
+ TxRateIdx = mcs[5];
+ else if (mcs[4]>=0 && (Rssi > -82))
+ TxRateIdx = mcs[4];
+ else if (mcs[4] == -1) /* for B-only mode */
+ TxRateIdx = mcs[3];
+ else if (mcs[3]>=0 && (Rssi > -85))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi > -87))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > -90))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+
+ return TxRateIdx;
+}
+
+/*
+ MlmeRAEstimateThroughput - estimate Throughput based on PER and PHY rate
+ pEntry - the MAC table entry for this STA
+ pCurrTxRate - pointer to Rate table entry for rate
+ TxErrorRatio - the PER
+*/
+static ULONG MlmeRAEstimateThroughput(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PRTMP_TX_RATE_SWITCH_3S pCurrTxRate,
+ IN ULONG TxErrorRatio)
+{
+ ULONG estTP = (100-TxErrorRatio)*pCurrTxRate->dataRate;
+
+ /* Adjust rates for MCS32-40MHz mapped to MCS0-20MHz and for non-CCK 40MHz */
+ if (pCurrTxRate->CurrMCS == MCS_32)
+ {
+#ifdef DBG_CTRL_SUPPORT
+ if ((pAd->CommonCfg.DebugFlags & DBF_DISABLE_20MHZ_MCS0)==0)
+ estTP /= 2;
+#endif /* DBG_CTRL_SUPPORT */
+ }
+ else if ((pCurrTxRate->Mode==MODE_HTMIX) || (pCurrTxRate->Mode==MODE_HTGREENFIELD))
+ {
+ if (pEntry->MaxHTPhyMode.field.BW==BW_40
+#ifdef DBG_CTRL_SUPPORT
+ || (pAd->CommonCfg.DebugFlags & DBF_FORCE_40MHZ)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ estTP *= 2;
+ }
+
+ return estTP;
+}
+
+/*
+ MlmeRAHybridRule - decide whether to keep the new rate or use old rate
+ pEntry - the MAC table entry for this STA
+ pCurrTxRate - pointer to Rate table entry for new up rate
+ NewTxOkCount - normalized count of Tx packets for new up rate
+ TxErrorRatio - the PER
+ returns
+ TRUE if old rate should be used
+*/
+BOOLEAN MlmeRAHybridRule(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PRTMP_TX_RATE_SWITCH_3S pCurrTxRate,
+ IN ULONG NewTxOkCount,
+ IN ULONG TxErrorRatio)
+{
+ ULONG newTP, oldTP;
+
+ if (100*NewTxOkCount < pAd->CommonCfg.TrainUpLowThrd*pEntry->LastTxOkCount)
+ return TRUE;
+
+ if (100*NewTxOkCount > pAd->CommonCfg.TrainUpHighThrd*pEntry->LastTxOkCount)
+ return FALSE;
+
+ newTP = MlmeRAEstimateThroughput(pAd, pEntry, pCurrTxRate, TxErrorRatio);
+ oldTP = MlmeRAEstimateThroughput(pAd, pEntry, PTX_RATE_SWITCH_ENTRY_3S(pEntry->pTable, pEntry->lastRateIdx), pEntry->LastTxPER);
+
+ return (oldTP > newTP);
+}
+
+/*
+ MlmeNewRateAdapt - perform Rate Adaptation based on PER using New RA algorithm
+ pEntry - the MAC table entry for this STA
+ UpRateIdx, DownRateIdx - UpRate and DownRate index
+ TrainUp, TrainDown - TrainUp and Train Down threhsolds
+ TxErrorRatio - the PER
+
+ On exit:
+ pEntry->LastSecTxRateChangeAction = RATE_UP or RATE_DOWN if there was a change
+ pEntry->CurrTxRateIndex = new rate index
+ pEntry->TxQuality is updated
+*/
+VOID MlmeNewRateAdapt(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR UpRateIdx,
+ IN UCHAR DownRateIdx,
+ IN ULONG TrainUp,
+ IN ULONG TrainDown,
+ IN ULONG TxErrorRatio)
+{
+ USHORT phyRateLimit20 = 0;
+ BOOLEAN bTrainUp = FALSE;
+#ifdef TXBF_SUPPORT
+ BOOLEAN invertTxBf = FALSE;
+#endif /* TXBF_SUPPORT */
+ UCHAR *pTable = pEntry->pTable;
+ UCHAR CurrRateIdx = pEntry->CurrTxRateIndex;
+ PRTMP_TX_RATE_SWITCH_3S pCurrTxRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, CurrRateIdx);
+
+ pEntry->CurrTxRateStableTime++;
+
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+
+
+ if (TxErrorRatio >= TrainDown)
+ {
+#ifdef TXBF_SUPPORT
+ PRTMP_TX_RATE_SWITCH_3S pDownRate, pLastNonBfRate;
+#endif /* TXBF_SUPPORT */
+
+ /* Downgrade TX quality if PER >= Rate-Down threshold */
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+
+#ifdef TXBF_SUPPORT
+ /*
+ Need to train down. If BF and last Non-BF is no worse than the down rate then
+ go to last Non-BF rate. Otherwise just go to the down rate
+ */
+
+ pDownRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, DownRateIdx);
+ pLastNonBfRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, pEntry->lastNonBfRate);
+
+ if ((pEntry->phyETxBf || pEntry->phyITxBf) &&
+ (pLastNonBfRate->dataRate >= pDownRate->dataRate)
+#ifdef DBG_CTRL_SUPPORT
+ && ((pAd->CommonCfg.DebugFlags & DBF_NO_BF_AWARE_RA)==0)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = pEntry->lastNonBfRate;
+ pEntry->LastSecTxRateChangeAction = RATE_DOWN;
+ }
+ else
+#endif /* TXBF_SUPPORT */
+ if (CurrRateIdx != DownRateIdx)
+ {
+ pEntry->CurrTxRateIndex = DownRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_DOWN;
+ }
+ }
+ else
+ {
+ PRTMP_TX_RATE_SWITCH_3S pUpRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, UpRateIdx);
+
+ /* Upgrade TX quality if PER <= Rate-Up threshold */
+ if (TxErrorRatio <= TrainUp)
+ {
+ bTrainUp = TRUE;
+ MlmeDecTxQuality(pEntry, CurrRateIdx); /* quality very good in CurrRate */
+
+ if (pEntry->TxRateUpPenalty) /* always == 0, always go to else */
+ pEntry->TxRateUpPenalty --;
+ else
+ {
+ /*
+ Decrement the TxQuality of the UpRate and all of the MCS groups.
+ Note that UpRate may mot equal one of the MCS groups if MlmeSelectUpRate
+ skipped over a rate that is not valid for this configuration.
+ */
+ MlmeDecTxQuality(pEntry, UpRateIdx);
+
+ if (pCurrTxRate->upMcs3!=CurrRateIdx &&
+ pCurrTxRate->upMcs3!=UpRateIdx)
+ MlmeDecTxQuality(pEntry, pCurrTxRate->upMcs3);
+
+ if (pCurrTxRate->upMcs2!=CurrRateIdx &&
+ pCurrTxRate->upMcs2!=UpRateIdx &&
+ pCurrTxRate->upMcs2!=pCurrTxRate->upMcs3)
+ MlmeDecTxQuality(pEntry, pCurrTxRate->upMcs2);
+
+ if (pCurrTxRate->upMcs1!=CurrRateIdx &&
+ pCurrTxRate->upMcs1!=UpRateIdx &&
+ pCurrTxRate->upMcs1!=pCurrTxRate->upMcs3 &&
+ pCurrTxRate->upMcs1!=pCurrTxRate->upMcs2)
+ MlmeDecTxQuality(pEntry, pCurrTxRate->upMcs1);
+ }
+ }
+ else if (pEntry->mcsGroup > 0) /* even if TxErrorRatio > TrainUp */
+ {
+ /* Moderate PER but some groups are not tried */
+ bTrainUp = TRUE;
+
+ /* TxQuality[CurrRateIdx] must be decremented so that mcs won't decrease wrongly */
+ MlmeDecTxQuality(pEntry, CurrRateIdx); /* quality very good in CurrRate */
+ MlmeDecTxQuality(pEntry, UpRateIdx); /* may improve next UP rate's quality */
+ }
+
+ /* Don't try up rate if it's greater than the limit */
+ if ((phyRateLimit20 != 0) && (pUpRate->dataRate >= phyRateLimit20))
+ return;
+
+ /* If UpRate is good then train up in current BF state */
+ if ((CurrRateIdx != UpRateIdx) && (MlmeGetTxQuality(pEntry, UpRateIdx) <= 0) && bTrainUp)
+ {
+ pEntry->CurrTxRateIndex = UpRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+#ifdef TXBF_SUPPORT
+ else
+#ifdef DBG_CTRL_SUPPORT
+ if ((pAd->CommonCfg.DebugFlags & DBF_NO_BF_AWARE_RA)==0)
+#endif /* DBG_CTRL_SUPPORT */
+ {
+ /* If not at the highest rate then try inverting BF state */
+ if (pEntry->phyETxBf || pEntry->phyITxBf)
+ {
+ /* If BF then try the same MCS non-BF unless PER is good */
+ if (TxErrorRatio > TrainUp)
+ {
+ if (pEntry->TxQuality[CurrRateIdx])
+ pEntry->TxQuality[CurrRateIdx]--;
+
+ if (pEntry->TxQuality[CurrRateIdx]==0)
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = CurrRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+ }
+ }
+ else if (pEntry->eTxBfEnCond>0 || pEntry->iTxBfEn)
+ {
+ /* First try Up Rate with BF */
+ if ((CurrRateIdx != UpRateIdx) &&
+ MlmeTxBfAllowed(pAd, pEntry, (PRTMP_TX_RATE_SWITCH)pUpRate))
+ {
+ if (pEntry->BfTxQuality[UpRateIdx])
+ pEntry->BfTxQuality[UpRateIdx]--;
+
+ if (pEntry->BfTxQuality[UpRateIdx]==0)
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = UpRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+ }
+
+ /* Try Same Rate if Up Rate failed */
+ if (pEntry->LastSecTxRateChangeAction==RATE_NO_CHANGE &&
+ MlmeTxBfAllowed(pAd, pEntry, (PRTMP_TX_RATE_SWITCH)pCurrTxRate))
+ {
+ if (pEntry->BfTxQuality[CurrRateIdx])
+ pEntry->BfTxQuality[CurrRateIdx]--;
+
+ if (pEntry->BfTxQuality[CurrRateIdx]==0)
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = CurrRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+ }
+ }
+ }
+#endif /* TXBF_SUPPORT */
+ }
+
+ /* Handle the rate change */
+ if ((pEntry->LastSecTxRateChangeAction != RATE_NO_CHANGE)
+#ifdef DBG_CTRL_SUPPORT
+ || (pAd->CommonCfg.DebugFlags & DBF_FORCE_QUICK_DRS)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ if (pEntry->LastSecTxRateChangeAction!=RATE_NO_CHANGE)
+ {
+ DBGPRINT_RAW(RT_DEBUG_INFO,("DRS: %sTX rate from %d to %d \n",
+ pEntry->LastSecTxRateChangeAction==RATE_UP? "++": "--", CurrRateIdx, pEntry->CurrTxRateIndex));
+ }
+
+ pEntry->CurrTxRateStableTime = 0;
+ pEntry->TxRateUpPenalty = 0;
+
+ /* Save last rate information */
+ pEntry->lastRateIdx = CurrRateIdx;
+#ifdef TXBF_SUPPORT
+ if (pEntry->eTxBfEnCond > 0)
+ {
+ pEntry->lastRatePhyTxBf = pEntry->phyETxBf;
+ pEntry->phyETxBf ^= invertTxBf;
+ }
+ else
+ {
+ pEntry->lastRatePhyTxBf = pEntry->phyITxBf;
+ pEntry->phyITxBf ^= invertTxBf;
+ }
+#endif /* TXBF_SUPPORT */
+
+ /* Update TxQuality */
+ if (pEntry->LastSecTxRateChangeAction == RATE_DOWN)
+ {
+ MlmeSetTxQuality(pEntry, pEntry->CurrTxRateIndex, 0);
+ pEntry->PER[pEntry->CurrTxRateIndex] = 0;
+ }
+
+ /* Set timer for check in 100 msec */
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ if (!pAd->ApCfg.ApQuickResponeForRateUpTimerRunning)
+ {
+ RTMPSetTimer(&pAd->ApCfg.ApQuickResponeForRateUpTimer, DEF_QUICK_RA_TIME_INTERVAL);
+ pAd->ApCfg.ApQuickResponeForRateUpTimerRunning = TRUE;
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* Update PHY rate */
+ MlmeNewTxRate(pAd, pEntry);
+ }
+}
+
+
+#ifdef CONFIG_AP_SUPPORT
+/*
+ ========================================================================
+ Routine Description:
+ AP side, Auto TxRate faster train up timer call back function.
+
+ Arguments:
+ SystemSpecific1 - Not used.
+ FunctionContext - Pointer to our Adapter context.
+ SystemSpecific2 - Not used.
+ SystemSpecific3 - Not used.
+
+ Return Value:
+ None
+
+ ========================================================================
+*/
+VOID APQuickResponeForRateUpExecAdapt(/* actually for both up and down */
+ IN PRTMP_ADAPTER pAd,
+ IN ULONG idx)
+{
+ PUCHAR pTable;
+ UCHAR CurrRateIdx;
+ ULONG AccuTxTotalCnt, TxTotalCnt, TxCnt;
+ ULONG TxErrorRatio = 0;
+ MAC_TABLE_ENTRY *pEntry;
+ PRTMP_TX_RATE_SWITCH_3S pCurrTxRate;
+ UCHAR TrainUp, TrainDown;
+ CHAR Rssi, ratio;
+ ULONG TxSuccess, TxRetransmit, TxFailCount;
+ ULONG OneSecTxNoRetryOKRationCount;
+ BOOLEAN rateChanged;
+#ifdef TXBF_SUPPORT
+ BOOLEAN CurrPhyETxBf, CurrPhyITxBf;
+#endif /* TXBF_SUPPORT */
+
+ pEntry = &pAd->MacTab.Content[idx];
+
+
+ pTable = pEntry->pTable;
+
+ /* Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); */
+ Rssi = RTMPAvgRssi(pAd, &pEntry->RssiSample);
+
+ if (pAd->MacTab.Size == 1)
+ {
+ TX_STA_CNT1_STRUC StaTx1;
+ TX_STA_CNT0_STRUC TxStaCnt0;
+
+ /* Update statistic counter */
+ NicGetTxRawCounters(pAd, &TxStaCnt0, &StaTx1);
+
+ TxRetransmit = StaTx1.field.TxRetransmit;
+ TxSuccess = StaTx1.field.TxSuccess;
+ TxFailCount = TxStaCnt0.field.TxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
+ pAd->RalinkCounters.OneSecTxRetryOkCount +
+ pAd->RalinkCounters.OneSecTxFailCount;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+
+ /* Rssi is calculated again with new formula?In rory's code, the average instead of max is used. */
+ if (pAd->Antenna.field.TxPath > 1)
+ Rssi = (pEntry->RssiSample.AvgRssi0 + pEntry->RssiSample.AvgRssi1) >> 1;
+ else
+ Rssi = pEntry->RssiSample.AvgRssi0;
+
+ TxCnt = AccuTxTotalCnt;
+ }
+ else
+ {
+ TxRetransmit = pEntry->OneSecTxRetryOkCount;
+ TxSuccess = pEntry->OneSecTxNoRetryOkCount;
+ TxFailCount = pEntry->OneSecTxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ TxCnt = TxTotalCnt;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+
+#ifdef FIFO_EXT_SUPPORT
+ if ((pEntry->Aid >= 1) && (pEntry->Aid <= 8))
+ {
+ ULONG HwTxCnt, HwErrRatio;
+
+ NicGetMacFifoTxCnt(pAd, pEntry);
+ HwTxCnt = pEntry->fifoTxSucCnt + pEntry->fifoTxRtyCnt;
+ if (HwTxCnt)
+ HwErrRatio = (pEntry->fifoTxRtyCnt * 100) / HwTxCnt;
+ else
+ HwErrRatio = 0;
+
+ DBGPRINT(RT_DEBUG_TRACE | DBG_FUNC_RA,("%s():Aid:%d, MCS:%d, TxErrRation(Hw:0x%lx-0x%lx, Sw:0x%lx-%lx)\n",
+ __FUNCTION__, pEntry->Aid, pEntry->HTPhyMode.field.MCS,
+ HwTxCnt, HwErrRatio, TxTotalCnt, TxErrorRatio));
+
+ TxSuccess = pEntry->fifoTxSucCnt;
+ TxRetransmit = pEntry->fifoTxRtyCnt;
+ TxErrorRatio = HwErrRatio;
+ TxTotalCnt = HwTxCnt;
+ TxCnt = HwTxCnt;
+ }
+#endif /* FIFO_EXT_SUPPORT */
+ }
+
+#ifdef MFB_SUPPORT
+ if (pEntry->fLastChangeAccordingMfb == TRUE)
+ {
+ pEntry->fLastChangeAccordingMfb = FALSE;
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA,("DRS: MCS is according to MFB, and ignore tuning this sec \n"));
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+ return;
+ }
+#endif /* MFB_SUPPORT */
+
+ /* Remember the current rate */
+ CurrRateIdx = pEntry->CurrTxRateIndex;
+#ifdef TXBF_SUPPORT
+ CurrPhyETxBf = pEntry->phyETxBf;
+ CurrPhyITxBf = pEntry->phyITxBf;
+#endif /* TXBF_SUPPORT */
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, CurrRateIdx);
+
+#ifdef DOT11_N_SUPPORT
+ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX) && pEntry->perThrdAdj == 1)
+ {
+ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
+ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {
+ TrainUp = pCurrTxRate->TrainUp;
+ TrainDown = pCurrTxRate->TrainDown;
+ }
+
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug option: Concise RA log */
+ if ((pAd->CommonCfg.DebugFlags & DBF_SHOW_RA_LOG) || (pAd->CommonCfg.DebugFlags & DBF_DBQ_RA_LOG))
+ MlmeRALog(pAd, pEntry, RAL_QUICK_DRS, TxErrorRatio, TxTotalCnt);
+#endif /* DBG_CTRL_SUPPORT */
+
+ /* Handle the low traffic case */
+ if (TxCnt <= 15)
+ {
+ /* Go back to the original rate */
+ MlmeRestoreLastRate(pEntry);
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA, (" QuickDRS: TxTotalCnt <= 15, back to original rate \n"));
+
+ MlmeNewTxRate(pAd, pEntry);
+
+
+ // TODO: should we reset all OneSecTx counters?
+ /* RESET_ONE_SEC_TX_CNT(pEntry); */
+
+ return;
+ }
+
+ /* Compare throughput. LastTxCount is based on a 500 msec or 500-DEF_QUICK_RA_TIME_INTERVAL interval. */
+ if ((pEntry->LastTimeTxRateChangeAction == RATE_NO_CHANGE)
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_FORCE_QUICK_DRS)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ ratio = RA_INTERVAL/DEF_QUICK_RA_TIME_INTERVAL;
+ else
+ ratio = (RA_INTERVAL-DEF_QUICK_RA_TIME_INTERVAL)/DEF_QUICK_RA_TIME_INTERVAL;
+
+ if (pAd->MacTab.Size == 1)
+ OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
+ else
+ OneSecTxNoRetryOKRationCount = pEntry->OneSecTxNoRetryOkCount * ratio + (pEntry->OneSecTxNoRetryOkCount >> 1);
+
+ /*
+ Downgrade TX quality if PER >= Rate-Down threshold
+ */
+ /* the only situation when pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND but no rate change */
+ if (TxErrorRatio >= TrainDown)
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+
+ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio;
+
+
+ /* Perform DRS - consider TxRate Down first, then rate up. */
+ if (pEntry->LastSecTxRateChangeAction == RATE_UP)
+ {
+ BOOLEAN useOldRate;
+
+ // TODO: gaa - Finalize the decision criterion
+ /*
+ 0=>Throughput. Use New Rate if New TP is better than Old TP
+ 1=>PER. Use New Rate if New PER is less than the TrainDown PER threshold
+ 2=>Hybrid. Use rate with best TP if difference > 10%. Otherwise use rate with Best Estimated TP
+ 3=>Hybrid with check that PER<TrainDown Threshold
+ */
+ if (pAd->CommonCfg.TrainUpRule == 0)
+ {
+ useOldRate = (pEntry->LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount;
+ }
+ else if (pAd->CommonCfg.TrainUpRule==2 && Rssi<=pAd->CommonCfg.TrainUpRuleRSSI)
+ {
+ useOldRate = MlmeRAHybridRule(pAd, pEntry, pCurrTxRate, OneSecTxNoRetryOKRationCount, TxErrorRatio);
+ }
+ else if (pAd->CommonCfg.TrainUpRule==3 && Rssi<=pAd->CommonCfg.TrainUpRuleRSSI)
+ {
+ useOldRate = (TxErrorRatio >= TrainDown) ||
+ MlmeRAHybridRule(pAd, pEntry, pCurrTxRate, OneSecTxNoRetryOKRationCount, TxErrorRatio);
+ }
+ else
+ useOldRate = TxErrorRatio >= TrainDown;
+ if (useOldRate)
+ {
+ /* If PER>50% or TP<lastTP/2 then double the TxQuality delay */
+ if ((TxErrorRatio > 50) || (OneSecTxNoRetryOKRationCount < pEntry->LastTxOkCount/2))
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND*2);
+ else
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+
+ MlmeRestoreLastRate(pEntry);
+ }
+ else
+ {
+ PRTMP_TX_RATE_SWITCH_3S pLastTxRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, pEntry->lastRateIdx);
+
+ /* Clear the history if we changed the MCS and PHY Rate */
+ if ((pCurrTxRate->CurrMCS != pLastTxRate->CurrMCS) &&
+ (pCurrTxRate->dataRate != pLastTxRate->dataRate))
+ MlmeClearTxQuality(pEntry);
+
+ if (pEntry->mcsGroup == 0)
+ MlmeSetMcsGroup(pAd, pEntry);
+
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA,
+ (" QuickDRS: (Up) keep rate-up (L:%ld, C:%ld)\n",
+ pEntry->LastTxOkCount, OneSecTxNoRetryOKRationCount));
+ }
+ }
+ else if (pEntry->LastSecTxRateChangeAction == RATE_DOWN)
+ {
+ if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) /* there will be train down again */
+ {
+ MlmeSetMcsGroup(pAd, pEntry);
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA,(" QuickDRS: (Down) direct train down (TxErrorRatio >= TrainDown)\n"));
+ }
+ else if ((pEntry->LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
+ {
+ MlmeRestoreLastRate(pEntry);
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA,(" QuickDRS: (Down) bad tx ok count (L:%ld, C:%ld)\n", pEntry->LastTxOkCount, OneSecTxNoRetryOKRationCount));
+ }
+ else
+ {
+ MlmeSetMcsGroup(pAd, pEntry);
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA,(" QuickDRS: (Down) keep rate-down (L:%ld, C:%ld)\n", pEntry->LastTxOkCount, OneSecTxNoRetryOKRationCount));
+ }
+ }
+
+ /* See if we reverted to the old rate */
+#ifdef TXBF_SUPPORT
+ rateChanged = (pEntry->CurrTxRateIndex != CurrRateIdx) ||
+ (pEntry->phyETxBf!=CurrPhyETxBf) || (pEntry->phyITxBf!=CurrPhyITxBf);
+
+ /* Remember last good non-BF rate */
+ if (!pEntry->phyETxBf && !pEntry->phyITxBf)
+ pEntry->lastNonBfRate = pEntry->CurrTxRateIndex;
+#else
+ rateChanged = (pEntry->CurrTxRateIndex != CurrRateIdx);
+#endif /* TXBF_SUPPORT */
+
+
+ /* Update mcsGroup */
+ if (pEntry->LastSecTxRateChangeAction == RATE_UP)
+ {
+ UCHAR UpRateIdx;
+
+ /* If RATE_UP failed look for the next group with valid mcs */
+ if (pEntry->CurrTxRateIndex != CurrRateIdx && pEntry->mcsGroup > 0)
+ {
+ pEntry->mcsGroup--;
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, pEntry->lastRateIdx);
+ }
+
+ switch (pEntry->mcsGroup)
+ {
+ case 3:
+ UpRateIdx = pCurrTxRate->upMcs3;
+ break;
+ case 2:
+ UpRateIdx = pCurrTxRate->upMcs2;
+ break;
+ case 1:
+ UpRateIdx = pCurrTxRate->upMcs1;
+ break;
+ default:
+ UpRateIdx = CurrRateIdx;
+ break;
+ }
+
+ if (UpRateIdx == pEntry->CurrTxRateIndex)
+ pEntry->mcsGroup = 0;
+ }
+
+
+ /* Handle change back to old rate */
+ if (rateChanged)
+ {
+ /* Clear Old Rate's TxQuality */
+ MlmeSetTxQuality(pEntry, pEntry->CurrTxRateIndex, 0);
+
+ pEntry->TxRateUpPenalty = 0; /* redundant */
+ pEntry->PER[pEntry->CurrTxRateIndex] = 0; /* redundant */
+
+ /* Set new Tx rate */
+ MlmeNewTxRate(pAd, pEntry);
+ }
+
+ // TODO: should we reset all OneSecTx counters?
+ /* RESET_ONE_SEC_TX_CNT(pEntry); */
+}
+
+
+
+/*
+ ==========================================================================
+ Description:
+ This routine walks through the MAC table, see if TX rate change is
+ required for each associated client.
+ Output:
+ pEntry->CurrTxRate -
+ NOTE:
+ call this routine every second
+ ==========================================================================
+ */
+VOID APMlmeDynamicTxRateSwitchingAdapt(
+ IN PRTMP_ADAPTER pAd, IN ULONG i)
+{
+ PUCHAR pTable;
+ UCHAR UpRateIdx, DownRateIdx, CurrRateIdx;
+ ULONG TxTotalCnt;
+ ULONG TxErrorRatio = 0;
+ MAC_TABLE_ENTRY *pEntry;
+ PRTMP_TX_RATE_SWITCH_3S pCurrTxRate;
+ UCHAR TrainUp, TrainDown;
+ CHAR Rssi;
+ ULONG TxSuccess, TxRetransmit, TxFailCount;
+#ifdef DOT11N_PF_DEBUG
+ UCHAR pEntryMaxMCS = 0, selfMaxMCS = 0;
+#endif /* DOT11N_PF_DEBUG */
+
+ pEntry = &pAd->MacTab.Content[i]; /* point to information of the individual station */
+ pTable = pEntry->pTable;
+
+ if (pAd->MacTab.Size == 1)
+ {
+ TX_STA_CNT1_STRUC StaTx1;
+ TX_STA_CNT0_STRUC TxStaCnt0;
+
+ /* Update statistic counter */
+ NicGetTxRawCounters(pAd, &TxStaCnt0, &StaTx1);
+
+ TxRetransmit = StaTx1.field.TxRetransmit;
+ TxSuccess = StaTx1.field.TxSuccess;
+ TxFailCount = TxStaCnt0.field.TxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+ }
+ else
+ {
+ TxRetransmit = pEntry->OneSecTxRetryOkCount;
+ TxSuccess = pEntry->OneSecTxNoRetryOkCount;
+ TxFailCount = pEntry->OneSecTxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+
+#ifdef FIFO_EXT_SUPPORT
+ if (pEntry->Aid >= 1 && pEntry->Aid <= 8)
+ {
+ ULONG HwTxCnt, HwErrRatio;
+
+ NicGetMacFifoTxCnt(pAd, pEntry);
+ HwTxCnt = pEntry->fifoTxSucCnt + pEntry->fifoTxRtyCnt;
+ if (HwTxCnt)
+ HwErrRatio = (pEntry->fifoTxRtyCnt * 100) / HwTxCnt;
+ else
+ HwErrRatio = 0;
+ DBGPRINT(RT_DEBUG_TRACE | DBG_FUNC_RA,("%s():Aid:%d, MCS:%d, TxErrRatio(Hw:0x%lx-0x%lx, Sw:0x%lx-%lx)\n",
+ __FUNCTION__, pEntry->Aid, pEntry->HTPhyMode.field.MCS,
+ HwTxCnt, HwErrRatio, TxTotalCnt, TxErrorRatio));
+
+ TxSuccess = pEntry->fifoTxSucCnt;
+ TxRetransmit = pEntry->fifoTxRtyCnt;
+ TxTotalCnt = HwTxCnt;
+ TxErrorRatio = HwErrRatio;
+ }
+#endif /* FIFO_EXT_SUPPORT */
+ }
+
+ /* Save LastTxOkCount, LastTxPER and last MCS action for APQuickResponeForRateUpExec */
+ pEntry->LastTxOkCount = TxSuccess;
+ pEntry->LastTxPER = (UCHAR)TxErrorRatio;
+ pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction;
+
+ /* different calculation in APQuickResponeForRateUpExec() */
+ /* Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); */
+ Rssi = RTMPAvgRssi(pAd, &pEntry->RssiSample);
+
+ /* decide the next upgrade rate and downgrade rate, if any */
+ CurrRateIdx = pEntry->CurrTxRateIndex;
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY_3S(pTable, CurrRateIdx);
+ UpRateIdx = MlmeSelectUpRate(pAd, pEntry, pCurrTxRate);
+ DownRateIdx = MlmeSelectDownRate(pAd, pEntry, CurrRateIdx);
+
+#ifdef DOT11N_PF_DEBUG
+ if (pEntry->HTCapability.MCSSet[0] == 0xff)
+ {
+ if (pEntry->HTCapability.MCSSet[1] == 0xff)
+ {
+ if(pEntry->HTCapability.MCSSet[2] == 0xff)
+ pEntryMaxMCS = 23;
+ else
+ pEntryMaxMCS = 15;
+ }
+ else
+ {
+ pEntryMaxMCS = 7;
+ }
+ }
+
+ if(pAd->CommonCfg.TxStream <= 3)
+ selfMaxMCS = 8 * pAd->CommonCfg.TxStream - 1;
+#endif /* DOT11N_PF_DEBUG */
+
+#ifdef DOT11_N_SUPPORT
+ /*
+ when Rssi > -65, there is a lot of interference usually. therefore, the algorithm tends to choose the mcs lower than the optimal one.
+ by increasing the thresholds, the chosen mcs will be closer to the optimal mcs
+ */
+ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX) && pEntry->perThrdAdj == 1)
+ {
+ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
+ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {
+ TrainUp = pCurrTxRate->TrainUp;
+ TrainDown = pCurrTxRate->TrainDown;
+ }
+
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug option: Concise RA log */
+ if ((pAd->CommonCfg.DebugFlags & DBF_SHOW_RA_LOG) || (pAd->CommonCfg.DebugFlags & DBF_DBQ_RA_LOG))
+ MlmeRALog(pAd, pEntry, RAL_NEW_DRS, TxErrorRatio, TxTotalCnt);
+#endif /* DBG_CTRL_SUPPORT */
+
+#ifdef MFB_SUPPORT
+ if (pEntry->fLastChangeAccordingMfb == TRUE)
+ {
+ PRTMP_TX_RATE_SWITCH pNextTxRate;
+
+ /* with this method mfb result can be applied every 500msec, instead of immediately */
+ NdisAcquireSpinLock(&pEntry->fLastChangeAccordingMfbLock);
+ pEntry->fLastChangeAccordingMfb = FALSE;
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+ NdisReleaseSpinLock(&pEntry->fLastChangeAccordingMfbLock);
+ APMlmeSetTxRate(pAd, pEntry, pEntry->LegalMfbRS);
+ DBGPRINT(RT_DEBUG_INFO,("DRS: MCS is according to MFB, and ignore tuning this sec \n"));
+ MlmeClearAllTxQuality(pEntry);/* clear all history, same as train up, purpose??? */
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+ pEntry->CurrTxRateIndex = (pEntry->LegalMfbRS)->ItemNo;
+ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*10];/* actually = pEntry->LegalMfbRS */
+ return;
+ }
+#endif /* MFB_SUPPORT */
+
+
+ /* Handle low traffic case */
+ if (TxTotalCnt <= 15)
+ {
+ pEntry->lowTrafficCount++;
+
+ if (pEntry->lowTrafficCount >= pAd->CommonCfg.lowTrafficThrd)
+ {
+ UCHAR TxRateIdx;
+ CHAR mcs[24];
+ CHAR RssiOffset = 0;
+
+ pEntry->lowTrafficCount = 0;
+
+ /* Check existence and get index of each MCS */
+ MlmeGetSupportedMcsAdapt(pAd, pEntry, GI_400, mcs);
+
+ if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||
+ (pTable == RateSwitchTable11N2S) || (pTable == RateSwitchTable11N2SForABand) ||
+ (pTable == RateSwitchTable))
+ {
+ RssiOffset = 2;
+ }
+ else if (ADAPT_RATE_TABLE(pTable))
+ {
+ RssiOffset = 0;
+ }
+ else
+ {
+ RssiOffset = 5;
+ }
+
+ /* Select the Tx rate based on the RSSI */
+ TxRateIdx = MlmeSelectTxRateAdapt(pAd, pEntry, mcs, Rssi, RssiOffset);
+
+ /* if (TxRateIdx != pEntry->CurrTxRateIndex) */
+ {
+ pEntry->lastRateIdx = pEntry->CurrTxRateIndex;
+ MlmeSetMcsGroup(pAd, pEntry);
+
+ pEntry->CurrTxRateIndex = TxRateIdx;
+#ifdef TXBF_SUPPORT
+ pEntry->phyETxBf = pEntry->phyITxBf = FALSE;
+#endif /* TXBF_SUPPORT */
+ MlmeNewTxRate(pAd, pEntry);
+ if (!pEntry->fLastSecAccordingRSSI)
+ {
+ DBGPRINT(RT_DEBUG_INFO,("DRS: TxTotalCnt <= 15, switch to MCS%d according to RSSI (%d), RssiOffset=%d\n", pEntry->HTPhyMode.field.MCS, Rssi, RssiOffset));
+ }
+ }
+
+ MlmeClearAllTxQuality(pEntry); /* clear all history */
+ pEntry->fLastSecAccordingRSSI = TRUE;
+ }
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+#ifdef TXBF_SUPPORT
+#ifdef DBG_CTRL_SUPPORT
+ /* In Unaware mode always try to send sounding */
+ if (pAd->CommonCfg.DebugFlags & DBF_NO_BF_AWARE_RA)
+ eTxBFProbing(pAd, pEntry);
+#endif /* DBG_CTRL_SUPPORT */
+#endif /* TXBF_SUPPORT */
+
+ return;
+ }
+
+ pEntry->lowTrafficCount = 0;
+
+ /*
+ After pEntry->fLastSecAccordingRSSI = TRUE; the for loop
+ continue. this condition is true when RateSwitching() is run
+ next time.
+ so the next rate adaptation is skipped. This mechanism is
+ deliberately designed by rory.
+ */
+ if (pEntry->fLastSecAccordingRSSI == TRUE)
+ {
+ pEntry->fLastSecAccordingRSSI = FALSE;
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+ /* DBGPRINT(RT_DEBUG_INFO,("DRS: MCS is according to RSSI, and ignore tuning this sec \n")); */
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+#ifdef TXBF_SUPPORT
+ if (pAd->chipCap.FlgHwTxBfCap)
+ eTxBFProbing(pAd, pEntry);
+#endif /* TXBF_SUPPORT */
+
+ return;
+ }
+
+ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio;
+
+ /* Select rate based on PER */
+ MlmeNewRateAdapt(pAd, pEntry, UpRateIdx, DownRateIdx, TrainUp, TrainDown, TxErrorRatio);
+
+#ifdef DOT11N_SS3_SUPPORT
+ /* Turn off RDG when 3s and rx count > tx count*5 */
+ MlmeCheckRDG(pAd, pEntry);
+#endif /* DOT11N_SS3_SUPPORT */
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+#ifdef TXBF_SUPPORT
+ if (pAd->chipCap.FlgHwTxBfCap)
+ eTxBFProbing(pAd, pEntry);
+#endif /* TXBF_SUPPORT */
+}
+#endif /* CONFIG_AP_SUPPORT */
+
+
+
+
+/*
+ Set_RateTable_Proc - Display or replace byte for item in RateSwitchTableAdapt11N3S
+ usage: iwpriv ra0 set RateTable=<item>[:<offset>:<value>]
+*/
+INT Set_RateTable_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ UCHAR *pTable, TableSize, InitTxRateIdx;
+ int i;
+ MAC_TABLE_ENTRY *pEntry;
+ int itemNo, rtIndex, value;
+ UCHAR *pRateEntry;
+
+ /* Find first Associated STA in MAC table */
+ for (i=1; i<MAX_LEN_OF_MAC_TABLE; i++)
+ {
+ pEntry = &pAd->MacTab.Content[i];
+ if (IS_ENTRY_CLIENT(pEntry) && pEntry->Sst==SST_ASSOC)
+ break;
+ }
+
+ if (i==MAX_LEN_OF_MAC_TABLE)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("Set_RateTable_Proc: Empty MAC Table\n"));
+ return FALSE;
+ }
+
+ /* Get peer's rate table */
+ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
+
+ /* Get rate index */
+ itemNo = simple_strtol(arg, &arg, 10);
+ if (itemNo<0 || itemNo>=RATE_TABLE_SIZE(pTable))
+ return FALSE;
+
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (ADAPT_RATE_TABLE(pTable))
+ pRateEntry = (UCHAR *)PTX_RATE_SWITCH_ENTRY_3S(pTable, itemNo);
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ pRateEntry = (UCHAR *)PTX_RATE_SWITCH_ENTRY(pTable, itemNo);
+
+ /* If no addtional parameters then print the entry */
+ if (*arg != ':') {
+ DBGPRINT(RT_DEBUG_OFF, ("Set_RateTable_Proc::%d\n", itemNo));
+ }
+ else {
+ /* Otherwise get the offset and the replace byte */
+ while (*arg<'0' || *arg>'9')
+ arg++;
+ rtIndex = simple_strtol(arg, &arg, 10);
+ if (rtIndex<0 || rtIndex>9)
+ return FALSE;
+
+ if (*arg!=':')
+ return FALSE;
+ while (*arg<'0' || *arg>'9')
+ arg++;
+ value = simple_strtol(arg, &arg, 10);
+ pRateEntry[rtIndex] = value;
+ DBGPRINT(RT_DEBUG_OFF, ("Set_RateTable_Proc::%d:%d:%d\n", itemNo, rtIndex, value));
+ }
+
+ DBGPRINT(RT_DEBUG_OFF, ("%d, 0x%02x, %d, %d, %d, %d, %d, %d, %d, %d\n",
+ pRateEntry[0], pRateEntry[1], pRateEntry[2], pRateEntry[3], pRateEntry[4],
+ pRateEntry[5], pRateEntry[6], pRateEntry[7], pRateEntry[8], pRateEntry[9]));
+
+ return TRUE;
+}
+
+
+INT Set_PerThrdAdj_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ UCHAR i;
+ for (i=0; i<MAX_LEN_OF_MAC_TABLE; i++){
+ pAd->MacTab.Content[i].perThrdAdj = simple_strtol(arg, 0, 10);
+ }
+ return TRUE;
+}
+
+/* Set_LowTrafficThrd_Proc - set threshold for reverting to default MCS based on RSSI */
+INT Set_LowTrafficThrd_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ pAd->CommonCfg.lowTrafficThrd = simple_strtol(arg, 0, 10);
+
+ return TRUE;
+}
+
+/* Set_TrainUpRule_Proc - set rule for Quick DRS train up */
+INT Set_TrainUpRule_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ pAd->CommonCfg.TrainUpRule = simple_strtol(arg, 0, 10);
+
+ return TRUE;
+}
+
+/* Set_TrainUpRuleRSSI_Proc - set RSSI threshold for Quick DRS Hybrid train up */
+INT Set_TrainUpRuleRSSI_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ pAd->CommonCfg.TrainUpRuleRSSI = simple_strtol(arg, 0, 10);
+
+ return TRUE;
+}
+
+/* Set_TrainUpLowThrd_Proc - set low threshold for Quick DRS Hybrid train up */
+INT Set_TrainUpLowThrd_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ pAd->CommonCfg.TrainUpLowThrd = simple_strtol(arg, 0, 10);
+
+ return TRUE;
+}
+
+/* Set_TrainUpHighThrd_Proc - set high threshold for Quick DRS Hybrid train up */
+INT Set_TrainUpHighThrd_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ pAd->CommonCfg.TrainUpHighThrd = simple_strtol(arg, 0, 10);
+
+ return TRUE;
+}
+
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+
diff --git a/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c
new file mode 100644
index 0000000000..3731678491
--- /dev/null
+++ b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c
@@ -0,0 +1,899 @@
+/****************************************************************************
+ * Ralink Tech Inc.
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2010, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************/
+
+/****************************************************************************
+
+ Abstract:
+
+ All related Dynamic Rate Switch (AP/STA) function body.
+
+ History:
+
+***************************************************************************/
+
+#include "rt_config.h"
+
+
+#ifdef CONFIG_AP_SUPPORT
+/*
+ ==========================================================================
+ Description:
+ This routine walks through the MAC table, see if TX rate change is
+ required for each associated client.
+ Output:
+ pEntry->CurrTxRate -
+ NOTE:
+ call this routine every second
+ ==========================================================================
+ */
+VOID APMlmeDynamicTxRateSwitching(
+ IN PRTMP_ADAPTER pAd)
+{
+ ULONG i;
+ PUCHAR pTable;
+ UCHAR TableSize = 0;
+ UCHAR UpRateIdx, DownRateIdx, CurrRateIdx;
+ ULONG TxTotalCnt;
+ ULONG TxErrorRatio = 0;
+ MAC_TABLE_ENTRY *pEntry;
+ PRTMP_TX_RATE_SWITCH pCurrTxRate, pTmpTxRate = NULL;
+ UCHAR InitTxRateIdx, TrainUp, TrainDown;
+ CHAR Rssi, TmpIdx = 0;
+ ULONG TxSuccess, TxRetransmit, TxFailCount;
+
+#ifdef RALINK_ATE
+ if (ATE_ON(pAd))
+ {
+ return;
+ }
+#endif /* RALINK_ATE */
+
+ /* walk through MAC table, see if need to change AP's TX rate toward each entry */
+ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++)
+ {
+ /* point to information of the individual station */
+ pEntry = &pAd->MacTab.Content[i];
+
+ if (IS_ENTRY_NONE(pEntry))
+ continue;
+
+ if (IS_ENTRY_CLIENT(pEntry) && (pEntry->Sst != SST_ASSOC))
+ continue;
+
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry) && (pEntry->Sst != SST_ASSOC))
+ continue;
+#endif /* APCLI_SUPPORT */
+
+#ifdef WDS_SUPPORT
+ if (IS_ENTRY_WDS(pEntry) && !WDS_IF_UP_CHECK(pAd, pEntry->MatchWDSTabIdx))
+ continue;
+#endif /* WDS_SUPPORT */
+
+
+ /* check if this entry need to switch rate automatically */
+ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
+ continue;
+
+
+ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
+ pEntry->pTable = pTable;
+
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (ADAPT_RATE_TABLE(pTable))
+ {
+ APMlmeDynamicTxRateSwitchingAdapt(pAd, i);
+
+ continue;
+ }
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+
+ /* NICUpdateFifoStaCounters(pAd); */
+
+ if (pAd->MacTab.Size == 1)
+ {
+ TX_STA_CNT1_STRUC StaTx1;
+ TX_STA_CNT0_STRUC TxStaCnt0;
+
+ /* Update statistic counter */
+ NicGetTxRawCounters(pAd, &TxStaCnt0, &StaTx1);
+
+ TxRetransmit = StaTx1.field.TxRetransmit;
+ TxSuccess = StaTx1.field.TxSuccess;
+ TxFailCount = TxStaCnt0.field.TxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+ }
+ else
+ {
+ TxRetransmit = pEntry->OneSecTxRetryOkCount;
+ TxSuccess = pEntry->OneSecTxNoRetryOkCount;
+ TxFailCount = pEntry->OneSecTxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+
+#ifdef FIFO_EXT_SUPPORT
+ if (pEntry->Aid >= 1 && pEntry->Aid <= 8)
+ {
+ ULONG HwTxCnt, HwErrRatio;
+
+ NicGetMacFifoTxCnt(pAd, pEntry);
+ HwTxCnt = pEntry->fifoTxSucCnt + pEntry->fifoTxRtyCnt;
+ if (HwTxCnt)
+ HwErrRatio = (pEntry->fifoTxRtyCnt * 100) / HwTxCnt;
+ else
+ HwErrRatio = 0;
+
+ DBGPRINT(RT_DEBUG_TRACE | DBG_FUNC_RA,
+ ("%s():Aid:%d, MCS:%d, CuTxRaIdx=%d,TxErrRatio(Hw:%d-%d%%, Sw:%d-%d%%)\n",
+ __FUNCTION__, pEntry->Aid, pEntry->HTPhyMode.field.MCS,
+ pEntry->CurrTxRateIndex,
+ HwTxCnt, HwErrRatio, TxTotalCnt, TxErrorRatio));
+
+ TxSuccess = pEntry->fifoTxSucCnt;
+ TxRetransmit = pEntry->fifoTxRtyCnt;
+ TxTotalCnt = HwTxCnt;
+ TxErrorRatio = HwErrRatio;
+ }
+#endif /* FIFO_EXT_SUPPORT */
+ }
+
+ /* Save LastTxOkCount, LastTxPER and last MCS action for APQuickResponeForRateUpExec */
+ pEntry->LastTxOkCount = TxSuccess;
+ pEntry->LastTxPER = (TxTotalCnt == 0 ? 0 : (UCHAR)TxErrorRatio);
+ pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction;
+
+ /* different calculation in APQuickResponeForRateUpExec() */
+ /* Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); */
+ Rssi = RTMPAvgRssi(pAd, &pEntry->RssiSample);
+
+ CurrRateIdx = UpRateIdx = DownRateIdx = pEntry->CurrTxRateIndex;
+
+ /* decide the next upgrade rate and downgrade rate, if any */
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY(pTable, CurrRateIdx);
+
+ if ((pCurrTxRate->Mode <= MODE_CCK) && (pEntry->SupportRateMode <= SUPPORT_CCK_MODE))
+ {
+ TmpIdx = CurrRateIdx + 1;
+ while(TmpIdx < TableSize)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportCCKMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ UpRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx++;
+ }
+
+ TmpIdx = CurrRateIdx - 1;
+ while(TmpIdx >= 0)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportCCKMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ DownRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx--;
+ }
+ }
+ else if ((pCurrTxRate->Mode <= MODE_OFDM) && (pEntry->SupportRateMode < SUPPORT_HT_MODE))
+ {
+ TmpIdx = CurrRateIdx + 1;
+ while(TmpIdx < TableSize)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportOFDMMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ UpRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx++;
+ }
+
+ TmpIdx = CurrRateIdx - 1;
+ while(TmpIdx >= 0)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportOFDMMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ DownRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx--;
+ }
+ }
+ else
+ {
+ /* decide the next upgrade rate and downgrade rate, if any*/
+ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1)))
+ {
+ TmpIdx = CurrRateIdx + 1;
+ while(TmpIdx < TableSize)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportHTMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ UpRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx++;
+ }
+
+ TmpIdx = CurrRateIdx - 1;
+ while(TmpIdx >= 0)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportHTMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ DownRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx--;
+ }
+ }
+ else if (CurrRateIdx == 0)
+ {
+ TmpIdx = CurrRateIdx + 1;
+ while(TmpIdx < TableSize)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportHTMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ UpRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx++;
+ }
+
+ DownRateIdx = CurrRateIdx;
+ }
+ else if (CurrRateIdx == (TableSize - 1))
+ {
+ UpRateIdx = CurrRateIdx;
+
+ TmpIdx = CurrRateIdx - 1;
+ while(TmpIdx >= 0)
+ {
+ pTmpTxRate = PTX_RATE_SWITCH_ENTRY(pTable, TmpIdx);
+ if (pEntry->SupportHTMCS[pTmpTxRate->CurrMCS] == TRUE)
+ {
+ DownRateIdx = TmpIdx;
+ break;
+ }
+ TmpIdx--;
+ }
+ }
+ }
+
+#ifdef DOT11_N_SUPPORT
+ /*
+ when Rssi > -65, there is a lot of interference usually. therefore, the algorithm
+ tends to choose the mcs lower than the optimal one.
+ by increasing the thresholds, the chosen mcs will be closer to the optimal mcs
+ */
+ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
+ {
+ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
+ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {
+ TrainUp = pCurrTxRate->TrainUp;
+ TrainDown = pCurrTxRate->TrainDown;
+ }
+
+
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug option: Concise RA log */
+ if (pAd->CommonCfg.DebugFlags & DBF_SHOW_RA_LOG)
+ MlmeRALog(pAd, pEntry, RAL_OLD_DRS, TxErrorRatio, TxTotalCnt);
+#endif /* DBG_CTRL_SUPPORT */
+
+
+ /* Check for low traffic case */
+ if (TxTotalCnt <= 15)
+ {
+ UCHAR TxRateIdx;
+ CHAR mcs[24];
+
+ /* Check existence and get the index of each MCS */
+ MlmeGetSupportedMcs(pAd, pTable, mcs);
+
+ /* Select the Tx rate based on the RSSI */
+ TxRateIdx = MlmeSelectTxRate(pAd, pEntry, mcs, Rssi, 0);
+
+
+ if (TxRateIdx != pEntry->CurrTxRateIndex
+#ifdef TXBF_SUPPORT
+ || pEntry->phyETxBf || pEntry->phyITxBf
+#endif /* TXBF_SUPPORT */
+ )
+ {
+ pEntry->CurrTxRateIndex = TxRateIdx;
+#ifdef TXBF_SUPPORT
+ pEntry->phyETxBf = pEntry->phyITxBf = FALSE;
+#endif /* TXBF_SUPPORT */
+ MlmeNewTxRate(pAd, pEntry);
+ if (!pEntry->fLastSecAccordingRSSI)
+ DBGPRINT(RT_DEBUG_INFO,("DRS: TxTotalCnt <= 15, switch MCS according to RSSI (%d)\n", Rssi));
+ }
+
+ MlmeClearAllTxQuality(pEntry);
+ pEntry->fLastSecAccordingRSSI = TRUE;
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+
+#ifdef TXBF_SUPPORT
+#ifdef DBG_CTRL_SUPPORT
+ /* In Unaware mode always try to send sounding */
+ if (pAd->CommonCfg.DebugFlags & DBF_NO_BF_AWARE_RA)
+ eTxBFProbing(pAd, pEntry);
+#endif /* DBG_CTRL_SUPPORT */
+#endif /* TXBF_SUPPORT */
+ continue;
+ }
+
+ if (pEntry->fLastSecAccordingRSSI == TRUE)
+ {
+ pEntry->fLastSecAccordingRSSI = FALSE;
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+#ifdef TXBF_SUPPORT
+ if (pAd->chipCap.FlgHwTxBfCap)
+ eTxBFProbing(pAd, pEntry);
+#endif /* TXBF_SUPPORT */
+
+ continue;
+ }
+
+ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio;
+
+ /* Select rate based on PER */
+ MlmeOldRateAdapt(pAd, pEntry, CurrRateIdx, UpRateIdx, DownRateIdx, TrainUp, TrainDown, TxErrorRatio);
+
+#ifdef DOT11N_SS3_SUPPORT
+ /* Turn off RDG when 3s and rx count > tx count*5 */
+ MlmeCheckRDG(pAd, pEntry);
+#endif /* DOT11N_SS3_SUPPORT */
+
+ /* reset all OneSecTx counters */
+ RESET_ONE_SEC_TX_CNT(pEntry);
+
+#ifdef TXBF_SUPPORT
+ if (pAd->chipCap.FlgHwTxBfCap)
+ eTxBFProbing(pAd, pEntry);
+#endif /* TXBF_SUPPORT */
+
+ }
+}
+
+
+/*
+ ========================================================================
+ Routine Description:
+ AP side, Auto TxRate faster train up timer call back function.
+
+ Arguments:
+ SystemSpecific1 - Not used.
+ FunctionContext - Pointer to our Adapter context.
+ SystemSpecific2 - Not used.
+ SystemSpecific3 - Not used.
+
+ Return Value:
+ None
+
+ ========================================================================
+*/
+VOID APQuickResponeForRateUpExec(
+ IN PVOID SystemSpecific1,
+ IN PVOID FunctionContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3)
+{
+ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext;
+ ULONG i;
+ PUCHAR pTable;
+ UCHAR TableSize = 0;
+ UCHAR CurrRateIdx;
+ ULONG AccuTxTotalCnt, TxTotalCnt, TxCnt;
+ ULONG TxErrorRatio = 0;
+ MAC_TABLE_ENTRY *pEntry;
+ PRTMP_TX_RATE_SWITCH pCurrTxRate;
+ UCHAR InitTxRateIdx, TrainUp, TrainDown;
+ CHAR Rssi, ratio;
+ ULONG TxSuccess, TxRetransmit, TxFailCount;
+#ifdef TXBF_SUPPORT
+ BOOLEAN CurrPhyETxBf, CurrPhyITxBf;
+#endif /* TXBF_SUPPORT */
+
+ pAd->ApCfg.ApQuickResponeForRateUpTimerRunning = FALSE;
+
+ /* walk through MAC table, see if need to change AP's TX rate toward each entry */
+ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++)
+ {
+ pEntry = &pAd->MacTab.Content[i];
+
+ if (IS_ENTRY_NONE(pEntry))
+ continue;
+
+ if (IS_ENTRY_CLIENT(pEntry) && (pEntry->Sst != SST_ASSOC))
+ continue;
+
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry) && (pEntry->Sst != SST_ASSOC))
+ continue;
+#endif /* APCLI_SUPPORT */
+
+#ifdef WDS_SUPPORT
+ if (IS_ENTRY_WDS(pEntry) && !WDS_IF_UP_CHECK(pAd, pEntry->MatchWDSTabIdx))
+ continue;
+#endif /* WDS_SUPPORT */
+
+
+
+ /* Do nothing if this entry didn't change */
+ if (pEntry->LastSecTxRateChangeAction == RATE_NO_CHANGE
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_FORCE_QUICK_DRS)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ continue;
+
+ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
+ pEntry->pTable = pTable;
+
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (ADAPT_RATE_TABLE(pTable))
+ {
+ APQuickResponeForRateUpExecAdapt(pAd, i);
+ continue;
+ }
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+
+ /*Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); */
+ Rssi = RTMPAvgRssi(pAd, &pEntry->RssiSample);
+
+
+ if (pAd->MacTab.Size == 1)
+ {
+ TX_STA_CNT1_STRUC StaTx1;
+ TX_STA_CNT0_STRUC TxStaCnt0;
+
+ /* Update statistic counter */
+ NicGetTxRawCounters(pAd, &TxStaCnt0, &StaTx1);
+
+ TxRetransmit = StaTx1.field.TxRetransmit;
+ TxSuccess = StaTx1.field.TxSuccess;
+ TxFailCount = TxStaCnt0.field.TxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
+ pAd->RalinkCounters.OneSecTxRetryOkCount +
+ pAd->RalinkCounters.OneSecTxFailCount;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+
+ if (pAd->Antenna.field.TxPath > 1)
+ Rssi = (pEntry->RssiSample.AvgRssi0 + pEntry->RssiSample.AvgRssi1) >> 1;
+ else
+ Rssi = pEntry->RssiSample.AvgRssi0;
+
+ TxCnt = AccuTxTotalCnt;
+ }
+ else
+ {
+ TxRetransmit = pEntry->OneSecTxRetryOkCount;
+ TxSuccess = pEntry->OneSecTxNoRetryOkCount;
+ TxFailCount = pEntry->OneSecTxFailCount;
+ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
+
+ TxCnt = TxTotalCnt;
+
+ if (TxTotalCnt)
+ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
+
+#ifdef FIFO_EXT_SUPPORT
+ if ((pEntry->Aid >= 1) && (pEntry->Aid <= 8))
+ {
+ ULONG HwTxCnt, HwErrRatio;
+
+ NicGetMacFifoTxCnt(pAd, pEntry);
+ HwTxCnt = pEntry->fifoTxSucCnt + pEntry->fifoTxRtyCnt;
+ if (HwTxCnt)
+ HwErrRatio = (pEntry->fifoTxRtyCnt * 100) / HwTxCnt;
+ else
+ HwErrRatio = 0;
+
+ DBGPRINT(RT_DEBUG_TRACE | DBG_FUNC_RA,("%s():Aid:%d, MCS:%d, TxErrRation(Hw:0x%lx-0x%lx, Sw:0x%lx-%lx)\n",
+ __FUNCTION__, pEntry->Aid, pEntry->HTPhyMode.field.MCS,
+ HwTxCnt, HwErrRatio, TxTotalCnt, TxErrorRatio));
+
+ TxSuccess = pEntry->fifoTxSucCnt;
+ TxRetransmit = pEntry->fifoTxRtyCnt;
+ TxErrorRatio = HwErrRatio;
+ TxTotalCnt = HwTxCnt;
+ TxCnt = HwTxCnt;
+ }
+#endif /* FIFO_EXT_SUPPORT */
+ }
+
+ CurrRateIdx = pEntry->CurrTxRateIndex;
+#ifdef TXBF_SUPPORT
+ CurrPhyETxBf = pEntry->phyETxBf;
+ CurrPhyITxBf = pEntry->phyITxBf;
+#endif /* TXBF_SUPPORT */
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY(pTable, CurrRateIdx);
+
+#ifdef DOT11_N_SUPPORT
+ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
+ {
+ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
+ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {
+ TrainUp = pCurrTxRate->TrainUp;
+ TrainDown = pCurrTxRate->TrainDown;
+ }
+
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug option: Concise RA log */
+ if (pAd->CommonCfg.DebugFlags & DBF_SHOW_RA_LOG)
+ MlmeRALog(pAd, pEntry, RAL_QUICK_DRS, TxErrorRatio, TxTotalCnt);
+#endif /* DBG_CTRL_SUPPORT */
+
+ if (TxCnt <= 15 && pEntry->HTPhyMode.field.MCS > 1)
+ {
+ MlmeClearAllTxQuality(pEntry);
+
+ /* Set current up MCS at the worst quality */
+ if (pEntry->LastSecTxRateChangeAction == RATE_UP)
+ {
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+ }
+
+ /* Go back to the original rate */
+ MlmeRestoreLastRate(pEntry);
+
+ MlmeNewTxRate(pAd, pEntry);
+
+
+ // TODO: should we reset all OneSecTx counters?
+ /* RESET_ONE_SEC_TX_CNT(pEntry); */
+
+ continue;
+ }
+
+ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio;
+
+ /* Compare throughput */
+ do
+ {
+ ULONG OneSecTxNoRetryOKRationCount;
+
+ /* Compare throughput. LastTxCount is based on a 500 msec or 500-DEF_QUICK_RA_TIME_INTERVAL interval. */
+ if ((pEntry->LastTimeTxRateChangeAction == RATE_NO_CHANGE)
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_FORCE_QUICK_DRS)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ ratio = RA_INTERVAL/DEF_QUICK_RA_TIME_INTERVAL;
+ else
+ ratio = (RA_INTERVAL-DEF_QUICK_RA_TIME_INTERVAL)/DEF_QUICK_RA_TIME_INTERVAL;
+
+ /* downgrade TX quality if PER >= Rate-Down threshold */
+ if (TxErrorRatio >= TrainDown)
+ {
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+ }
+
+ if (pAd->MacTab.Size == 1)
+ {
+ OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
+ }
+ else
+ {
+ OneSecTxNoRetryOKRationCount = pEntry->OneSecTxNoRetryOkCount * ratio + (pEntry->OneSecTxNoRetryOkCount >> 1);
+ }
+
+ /* perform DRS - consider TxRate Down first, then rate up. */
+ if (pEntry->LastSecTxRateChangeAction == RATE_UP)
+ {
+// TODO: gaa - use different criterion for train up in Old RA?
+ /*if ((pEntry->LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) */
+ if (TxErrorRatio >= TrainDown)
+ {
+#ifdef TXBF_SUPPORT
+ /* If PER>50% or TP<lastTP/2 then double the TxQuality delay */
+ if ((TxErrorRatio > 50) || (OneSecTxNoRetryOKRationCount < pEntry->LastTxOkCount/2))
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND*2);
+ else
+#endif /* TXBF_SUPPORT */
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+
+ MlmeRestoreLastRate(pEntry);
+ }
+ else
+ {
+ }
+ }
+ else if (pEntry->LastSecTxRateChangeAction == RATE_DOWN)
+ {
+ /* if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) */
+ if ((TxErrorRatio >= 50) && (TxErrorRatio >= TrainDown))
+ {
+ }
+ else if ((pEntry->LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
+ {
+ MlmeRestoreLastRate(pEntry);
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_RA,("QuickDRS: (Down) keep rate-down (L:%ld, C:%ld)\n", pEntry->LastTxOkCount, OneSecTxNoRetryOKRationCount));
+ }
+ }
+ }while (FALSE);
+
+#ifdef TXBF_SUPPORT
+ /* Remember last good non-BF rate */
+ if (!pEntry->phyETxBf && !pEntry->phyITxBf)
+ pEntry->lastNonBfRate = pEntry->CurrTxRateIndex;
+#endif /* TXBF_SUPPORT */
+
+ /* If rate changed then update the history and set the new tx rate */
+ if ((pEntry->CurrTxRateIndex != CurrRateIdx)
+#ifdef TXBF_SUPPORT
+ || (pEntry->phyETxBf!=CurrPhyETxBf) || (pEntry->phyITxBf!=CurrPhyITxBf)
+#endif /* TXBF_SUPPORT */
+ )
+ {
+ /* if rate-up happen, clear all bad history of all TX rates */
+ if (pEntry->LastSecTxRateChangeAction == RATE_DOWN)
+ {
+ pEntry->TxRateUpPenalty = 0;
+ if (pEntry->CurrTxRateIndex != CurrRateIdx)
+ MlmeClearTxQuality(pEntry);
+ }
+ /* if rate-down happen, only clear DownRate's bad history */
+ else if (pEntry->LastSecTxRateChangeAction == RATE_UP)
+ {
+ pEntry->TxRateUpPenalty = 0; /* no penalty */
+ MlmeSetTxQuality(pEntry, pEntry->CurrTxRateIndex, 0);
+ pEntry->PER[pEntry->CurrTxRateIndex] = 0;
+ }
+
+ MlmeNewTxRate(pAd, pEntry);
+ }
+
+ // TODO: should we reset all OneSecTx counters?
+ /* RESET_ONE_SEC_TX_CNT(pEntry); */
+ }
+}
+#endif /* CONFIG_AP_SUPPORT */
+
+
+
+
+/*
+ MlmeOldRateAdapt - perform Rate Adaptation based on PER using old RA algorithm
+ pEntry - the MAC table entry
+ CurrRateIdx - the index of the current rate
+ UpRateIdx, DownRateIdx - UpRate and DownRate index
+ TrainUp, TrainDown - TrainUp and Train Down threhsolds
+ TxErrorRatio - the PER
+
+ On exit:
+ pEntry->LastSecTxRateChangeAction = RATE_UP or RATE_DOWN if there was a change
+ pEntry->CurrTxRateIndex = new rate index
+ pEntry->TxQuality is updated
+*/
+VOID MlmeOldRateAdapt(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR CurrRateIdx,
+ IN UCHAR UpRateIdx,
+ IN UCHAR DownRateIdx,
+ IN ULONG TrainUp,
+ IN ULONG TrainDown,
+ IN ULONG TxErrorRatio)
+{
+ BOOLEAN bTrainUp = FALSE;
+#ifdef TXBF_SUPPORT
+ UCHAR *pTable = pEntry->pTable;
+ BOOLEAN invertTxBf = FALSE;
+#endif /* TXBF_SUPPORT */
+
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+
+ pEntry->CurrTxRateStableTime++;
+
+ /* Downgrade TX quality if PER >= Rate-Down threshold */
+ if (TxErrorRatio >= TrainDown)
+ {
+ MlmeSetTxQuality(pEntry, CurrRateIdx, DRS_TX_QUALITY_WORST_BOUND);
+#ifdef TXBF_SUPPORT
+ /*
+ Need to train down. If BF and last Non-BF isn't too much lower then
+ go to last Non-BF rate. Otherwise just go to the down rate
+ */
+ if ((pEntry->phyETxBf || pEntry->phyITxBf) &&
+ (DownRateIdx - pEntry->lastNonBfRate)<2
+#ifdef DBG_CTRL_SUPPORT
+ && ((pAd->CommonCfg.DebugFlags & DBF_NO_BF_AWARE_RA)==0)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ /* Go directly to last non-BF rate without 100 msec check */
+ pEntry->CurrTxRateIndex = pEntry->lastNonBfRate;
+ pEntry->phyETxBf = pEntry->phyITxBf = FALSE;
+ MlmeNewTxRate(pAd, pEntry);
+ DBGPRINT_RAW(RT_DEBUG_INFO | DBG_FUNC_RA,("DRS: --TX rate from %d to %d \n", CurrRateIdx, pEntry->CurrTxRateIndex));
+ return;
+ }
+ else
+#endif /* TXBF_SUPPORT */
+ if (CurrRateIdx != DownRateIdx)
+ {
+ pEntry->CurrTxRateIndex = DownRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_DOWN;
+ }
+ }
+ else
+ {
+ /* Upgrade TX quality if PER <= Rate-Up threshold */
+ if (TxErrorRatio <= TrainUp)
+ {
+ bTrainUp = TRUE;
+ MlmeDecTxQuality(pEntry, CurrRateIdx); /* quality very good in CurrRate */
+
+ if (pEntry->TxRateUpPenalty)
+ pEntry->TxRateUpPenalty --;
+ else
+ MlmeDecTxQuality(pEntry, UpRateIdx); /* may improve next UP rate's quality */
+ }
+
+ if (bTrainUp)
+ {
+ /* Train up if up rate quality is 0 */
+ if ((CurrRateIdx != UpRateIdx) && (MlmeGetTxQuality(pEntry, UpRateIdx) <= 0))
+ {
+ pEntry->CurrTxRateIndex = UpRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+#ifdef TXBF_SUPPORT
+ else if (((CurrRateIdx != UpRateIdx) || (TxErrorRatio > TrainUp))
+#ifdef DBG_CTRL_SUPPORT
+ && ((pAd->CommonCfg.DebugFlags & DBF_NO_BF_AWARE_RA)==0)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ /* UpRate TxQuality is not 0. Try to invert BF state */
+ if (pEntry->phyETxBf || pEntry->phyITxBf)
+ {
+ /* BF tries same MCS, non-BF */
+ if (pEntry->TxQuality[CurrRateIdx])
+ pEntry->TxQuality[CurrRateIdx]--;
+
+ if (pEntry->TxQuality[CurrRateIdx]==0)
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = CurrRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+ }
+ else if (pEntry->eTxBfEnCond>0 || pEntry->iTxBfEn)
+ {
+ PRTMP_TX_RATE_SWITCH pUpRate = PTX_RATE_SWITCH_ENTRY(pTable, UpRateIdx);
+ PRTMP_TX_RATE_SWITCH pCurrTxRate = PTX_RATE_SWITCH_ENTRY(pTable, CurrRateIdx);
+
+ /* First try Up Rate with BF */
+ if ((CurrRateIdx != UpRateIdx) && MlmeTxBfAllowed(pAd, pEntry, pUpRate))
+ {
+ if (pEntry->BfTxQuality[UpRateIdx])
+ pEntry->BfTxQuality[UpRateIdx]--;
+
+ if (pEntry->BfTxQuality[UpRateIdx]==0)
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = UpRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+ }
+
+ /* Try Same Rate if Up Rate failed */
+ if (pEntry->LastSecTxRateChangeAction==RATE_NO_CHANGE &&
+ MlmeTxBfAllowed(pAd, pEntry, pCurrTxRate))
+ {
+ if (pEntry->BfTxQuality[CurrRateIdx])
+ pEntry->BfTxQuality[CurrRateIdx]--;
+
+ if (pEntry->BfTxQuality[CurrRateIdx]==0)
+ {
+ invertTxBf = TRUE;
+ pEntry->CurrTxRateIndex = CurrRateIdx;
+ pEntry->LastSecTxRateChangeAction = RATE_UP;
+ }
+ }
+ }
+ }
+#endif /* TXBF_SUPPORT */
+ }
+ }
+
+ /* Handle the rate change */
+ if (pEntry->LastSecTxRateChangeAction != RATE_NO_CHANGE)
+ {
+ pEntry->CurrTxRateStableTime = 0;
+ pEntry->TxRateUpPenalty = 0;
+
+ /* Save last rate information */
+ pEntry->lastRateIdx = CurrRateIdx;
+#ifdef TXBF_SUPPORT
+ if (pEntry->eTxBfEnCond>0)
+ {
+ pEntry->lastRatePhyTxBf = pEntry->phyETxBf;
+ pEntry->phyETxBf ^= invertTxBf;
+ }
+ else
+ {
+ pEntry->lastRatePhyTxBf = pEntry->phyITxBf;
+ pEntry->phyITxBf ^= invertTxBf;
+ }
+#endif /* TXBF_SUPPORT */
+
+ /* Update TxQuality */
+ if (pEntry->LastSecTxRateChangeAction == RATE_UP)
+ {
+ /* Clear history if normal train up */
+ if (pEntry->lastRateIdx != pEntry->CurrTxRateIndex)
+ MlmeClearTxQuality(pEntry);
+ }
+ else
+ {
+ /* Clear the down rate history */
+ MlmeSetTxQuality(pEntry, pEntry->CurrTxRateIndex, 0);
+ pEntry->PER[pEntry->CurrTxRateIndex] = 0;
+ }
+
+ /* Set timer for check in 100 msec */
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ if (!pAd->ApCfg.ApQuickResponeForRateUpTimerRunning)
+ {
+ RTMPSetTimer(&pAd->ApCfg.ApQuickResponeForRateUpTimer, DEF_QUICK_RA_TIME_INTERVAL);
+ pAd->ApCfg.ApQuickResponeForRateUpTimerRunning = TRUE;
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* Update PHY rate */
+ MlmeNewTxRate(pAd, pEntry);
+ }
+}
diff --git a/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/ra_ctrl.c b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/ra_ctrl.c
new file mode 100644
index 0000000000..b790d8b0ee
--- /dev/null
+++ b/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/ra_ctrl.c
@@ -0,0 +1,1751 @@
+/****************************************************************************
+ * Ralink Tech Inc.
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2010, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************/
+
+#include "rt_config.h"
+
+
+UCHAR RateSwitchTable[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x11, 0x00, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 35, 45,
+ 0x03, 0x00, 3, 20, 45,
+ 0x04, 0x21, 0, 30, 50,
+ 0x05, 0x21, 1, 20, 50,
+ 0x06, 0x21, 2, 20, 50,
+ 0x07, 0x21, 3, 15, 50,
+ 0x08, 0x21, 4, 15, 30,
+ 0x09, 0x21, 5, 10, 25,
+ 0x0a, 0x21, 6, 8, 25,
+ 0x0b, 0x21, 7, 8, 25,
+ 0x0c, 0x20, 12, 15, 30,
+ 0x0d, 0x20, 13, 8, 20,
+ 0x0e, 0x20, 14, 8, 20,
+ 0x0f, 0x20, 15, 8, 25,
+ 0x10, 0x22, 15, 8, 25,
+ 0x11, 0x00, 0, 0, 0,
+ 0x12, 0x00, 0, 0, 0,
+ 0x13, 0x00, 0, 0, 0,
+ 0x14, 0x00, 0, 0, 0,
+ 0x15, 0x00, 0, 0, 0,
+ 0x16, 0x00, 0, 0, 0,
+ 0x17, 0x00, 0, 0, 0,
+ 0x18, 0x00, 0, 0, 0,
+ 0x19, 0x00, 0, 0, 0,
+ 0x1a, 0x00, 0, 0, 0,
+ 0x1b, 0x00, 0, 0, 0,
+ 0x1c, 0x00, 0, 0, 0,
+ 0x1d, 0x00, 0, 0, 0,
+ 0x1e, 0x00, 0, 0, 0,
+ 0x1f, 0x00, 0, 0, 0,
+};
+
+
+UCHAR RateSwitchTable11B[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x04, 0x03, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 35, 45,
+ 0x03, 0x00, 3, 20, 45,
+};
+
+UCHAR RateSwitchTable11BG[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0a, 0x00, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 35, 45,
+ 0x03, 0x00, 3, 20, 45,
+ 0x04, 0x10, 2, 20, 35,
+ 0x05, 0x10, 3, 16, 35,
+ 0x06, 0x10, 4, 10, 25,
+ 0x07, 0x10, 5, 16, 25,
+ 0x08, 0x10, 6, 10, 25,
+ 0x09, 0x10, 7, 10, 13,
+};
+
+UCHAR RateSwitchTable11G[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x08, 0x00, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x10, 0, 20, 101,
+ 0x01, 0x10, 1, 20, 35,
+ 0x02, 0x10, 2, 20, 35,
+ 0x03, 0x10, 3, 16, 35,
+ 0x04, 0x10, 4, 10, 25,
+ 0x05, 0x10, 5, 16, 25,
+ 0x06, 0x10, 6, 10, 25,
+ 0x07, 0x10, 7, 10, 13,
+};
+
+
+#ifdef DOT11_N_SUPPORT
+UCHAR RateSwitchTable11N1S[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0c, 0x0a, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 25, 45,
+ 0x03, 0x21, 0, 20, 35,
+ 0x04, 0x21, 1, 20, 35,
+ 0x05, 0x21, 2, 20, 35,
+ 0x06, 0x21, 3, 15, 35,
+ 0x07, 0x21, 4, 15, 30,
+ 0x08, 0x21, 5, 10, 25,
+ 0x09, 0x21, 6, 8, 14,
+ 0x0a, 0x21, 7, 8, 14,
+ 0x0b, 0x23, 7, 8, 14,
+};
+
+
+UCHAR RateSwitchTable11N2S[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0e, 0x0c, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 25, 45,
+ 0x03, 0x21, 0, 20, 35,
+ 0x04, 0x21, 1, 20, 35,
+ 0x05, 0x21, 2, 20, 35,
+ 0x06, 0x21, 3, 15, 35,
+ 0x07, 0x21, 4, 15, 30,
+ 0x08, 0x20, 11, 15, 30,
+ 0x09, 0x20, 12, 15, 30,
+ 0x0a, 0x20, 13, 8, 20,
+ 0x0b, 0x20, 14, 8, 20,
+ 0x0c, 0x20, 15, 8, 25,
+ 0x0d, 0x22, 15, 8, 15,
+};
+
+
+UCHAR RateSwitchTable11N3S[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x11, 0x0c, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 25, 45,
+ 0x03, 0x21, 0, 20, 35,
+ 0x04, 0x21, 1, 20, 35,
+ 0x05, 0x21, 2, 20, 35,
+ 0x06, 0x21, 3, 15, 35,
+ 0x07, 0x21, 4, 15, 30,
+ 0x08, 0x20, 11, 15, 30,
+ 0x09, 0x20, 12, 15, 22,
+ 0x0a, 0x20, 13, 8, 20,
+ 0x0b, 0x20, 14, 8, 20,
+ 0x0c, 0x20, 20, 8, 20,
+ 0x0d, 0x20, 21, 8, 20,
+ 0x0e, 0x20, 22, 8, 20,
+ 0x0f, 0x20, 23, 8, 20,
+ 0x10, 0x22, 23, 8, 15,
+};
+
+
+UCHAR RateSwitchTable11BGN1S[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0c, 0x0a, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 25, 45,
+ 0x03, 0x21, 0, 20, 35,
+ 0x04, 0x21, 1, 20, 35,
+ 0x05, 0x21, 2, 20, 35,
+ 0x06, 0x21, 3, 15, 35,
+ 0x07, 0x21, 4, 15, 30,
+ 0x08, 0x21, 5, 10, 25,
+ 0x09, 0x21, 6, 8, 14,
+ 0x0a, 0x21, 7, 8, 14,
+ 0x0b, 0x23, 7, 8, 14,
+};
+
+
+UCHAR RateSwitchTable11BGN2S[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0e, 0x0c, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x00, 0, 40, 101,
+ 0x01, 0x00, 1, 40, 50,
+ 0x02, 0x00, 2, 25, 45,
+ 0x03, 0x21, 0, 20, 35,
+ 0x04, 0x21, 1, 20, 35,
+ 0x05, 0x21, 2, 20, 35,
+ 0x06, 0x21, 3, 15, 35,
+ 0x07, 0x21, 4, 15, 30,
+ 0x08, 0x20, 11, 15, 30,
+ 0x09, 0x20, 12, 15, 22,
+ 0x0a, 0x20, 13, 8, 20,
+ 0x0b, 0x20, 14, 8, 20,
+ 0x0c, 0x20, 15, 8, 20,
+ 0x0d, 0x22, 15, 8, 15,
+};
+
+
+UCHAR RateSwitchTable11BGN3S[] = { /* 3*3*/
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0e, 0x00, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x21, 0, 30,101, /*50*/
+ 0x01, 0x21, 1, 20, 50,
+ 0x02, 0x21, 2, 20, 50,
+ 0x03, 0x21, 3, 20, 50,
+ 0x04, 0x21, 4, 15, 50,
+ 0x05, 0x20, 11, 15, 30,
+ 0x06, 0x20, 12, 15, 30,
+ 0x07, 0x20, 13, 8, 20,
+ 0x08, 0x20, 14, 8, 20,
+ 0x09, 0x20, 15, 8, 25,
+ /*0x0a, 0x20, 20, 15, 30,*/
+ 0x0a, 0x20, 21, 8, 20,
+ 0x0b, 0x20, 22, 8, 20,
+ 0x0c, 0x20, 23, 8, 25,
+ 0x0d, 0x22, 23, 8, 25,
+};
+
+
+UCHAR RateSwitchTable11N1SForABand[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown */
+/* Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
+ 0x09, 0x07, 0, 0, 0, /* Initial used item after association */
+ 0x00, 0x21, 0, 30, 101,
+ 0x01, 0x21, 1, 20, 50,
+ 0x02, 0x21, 2, 20, 50,
+ 0x03, 0x21, 3, 15, 50,
+ 0x04, 0x21, 4, 15, 30,
+ 0x05, 0x21, 5, 10, 25,
+ 0x06, 0x21, 6, 8, 14,
+ 0x07, 0x21, 7, 8, 14,
+ 0x08, 0x23, 7, 8, 14,
+};
+
+
+UCHAR RateSwitchTable11N2SForABand[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0b, 0x09, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x21, 0, 30, 101,
+ 0x01, 0x21, 1, 20, 50,
+ 0x02, 0x21, 2, 20, 50,
+ 0x03, 0x21, 3, 15, 50,
+ 0x04, 0x21, 4, 15, 30,
+ 0x05, 0x21, 5, 15, 30,
+ 0x06, 0x20, 12, 15, 30,
+ 0x07, 0x20, 13, 8, 20,
+ 0x08, 0x20, 14, 8, 20,
+ 0x09, 0x20, 15, 8, 25,
+ 0x0a, 0x22, 15, 8, 25,
+};
+
+
+UCHAR RateSwitchTable11BGN2SForABand[] = {
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0b, 0x09, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x21, 0, 30,101, /*50*/
+ 0x01, 0x21, 1, 20, 50,
+ 0x02, 0x21, 2, 20, 50,
+ 0x03, 0x21, 3, 15, 50,
+ 0x04, 0x21, 4, 15, 30,
+ 0x05, 0x21, 5, 15, 30,
+ 0x06, 0x20, 12, 15, 30,
+ 0x07, 0x20, 13, 8, 20,
+ 0x08, 0x20, 14, 8, 20,
+ 0x09, 0x20, 15, 8, 25,
+ 0x0a, 0x22, 15, 8, 25,
+};
+
+
+UCHAR RateSwitchTable11N3SForABand[] = { /* 3*3*/
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0e, 0x09, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x21, 0, 30, 101,
+ 0x01, 0x21, 1, 20, 50,
+ 0x02, 0x21, 2, 20, 50,
+ 0x03, 0x21, 3, 15, 50,
+ 0x04, 0x21, 4, 15, 30,
+ 0x05, 0x21, 5, 15, 30,
+ 0x06, 0x20, 12, 15, 30,
+ 0x07, 0x20, 13, 8, 20,
+ 0x08, 0x20, 14, 8, 20,
+ 0x09, 0x20, 15, 8, 25,
+ /*0x0a, 0x22, 15, 8, 25,*/
+ /*0x0a, 0x20, 20, 15, 30,*/
+ 0x0a, 0x20, 21, 8, 20,
+ 0x0b, 0x20, 22, 8, 20,
+ 0x0c, 0x20, 23, 8, 25,
+ 0x0d, 0x22, 23, 8, 25,
+};
+
+
+UCHAR RateSwitchTable11BGN3SForABand[] = { /* 3*3*/
+/* Item No. Mode Curr-MCS TrainUp TrainDown Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)*/
+ 0x0e, 0x09, 0, 0, 0, /* Initial used item after association*/
+ 0x00, 0x21, 0, 30,101, /*50*/
+ 0x01, 0x21, 1, 20, 50,
+ 0x02, 0x21, 2, 20, 50,
+ 0x03, 0x21, 3, 15, 50,
+ 0x04, 0x21, 4, 15, 30,
+ 0x05, 0x21, 5, 15, 30,
+ 0x06, 0x20, 12, 15, 30,
+ 0x07, 0x20, 13, 8, 20,
+ 0x08, 0x20, 14, 8, 20,
+ 0x09, 0x20, 15, 8, 25,
+ /*0x0a, 0x22, 15, 8, 25,*/
+ /*0x0a, 0x20, 20, 15, 30,*/
+ 0x0a, 0x20, 21, 8, 20,
+ 0x0b, 0x20, 22, 8, 20,
+ 0x0c, 0x20, 23, 8, 25,
+ 0x0d, 0x22, 23, 8, 25,
+};
+
+
+#ifdef NEW_RATE_ADAPT_SUPPORT
+
+#ifdef RANGE_EXTEND
+#define SUPPORT_SHORT_GI_RA /* Support switching to Short GI rates in RA */
+#endif /* RANGE_EXTEND */
+
+/*
+ Rate switch tables for New Rate Adaptation
+
+ Each row has 10 bytes of data.
+ First row contains table information:
+ Byte0=the number of rate entries, Byte1=the initial rate.
+ Format of Mode byte:
+ Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
+*/
+UCHAR RateSwitchTableAdapt11N1S[] = {
+/* item no. mcs highPERThrd upMcs3 upMcs1
+ mode lowPERThrd downMcs upMcs2
+*/
+ 12, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x21, 0, 30, 50, 11, 1, 8, 1, 7,/* mcs0 */
+ 1, 0x21, 1, 20, 50, 0, 16, 9, 2, 13,/* mcs1 */
+ 2, 0x21, 2, 20, 50, 1, 17, 9, 3, 20,/* mcs2 */
+ 3, 0x21, 3, 15, 50, 2, 17, 10, 4, 26,/* mcs3 */
+ 4, 0x21, 4, 15, 30, 3, 18, 11, 5, 39,/* mcs4 */
+ 5, 0x21, 5, 10, 25, 4, 18, 12, 6, 52,/* mcs5 */
+ 6, 0x21, 6, 8, 14, 5, 19, 12, 7, 59,/* mcs6 */
+ 7, 0x21, 7, 8, 14, 6, 19, 12, 8, 65,/* mcs7 */
+ 8, 0x23, 7, 8, 14, 7, 19, 12, 8, 72,/* mcs7+short gi */
+
+ 9, 0x00, 0, 40, 101, 9 , 9, 9, 10, 1, /* cck-1M */
+ 10, 0x00, 1, 40, 50, 9, 10, 10, 11, 2, /* cck-2M */
+ 11, 0x21, 32, 30, 50, 10, 0, 8, 0, 7, /* mcs32 or 20M/mcs0 */
+};
+
+#ifdef SUPPORT_SHORT_GI_RA
+/* Indices for Short GI rates in 11N2S table */
+ #define sg07 18 /* mcs7+shortGI index */
+ #define sg14 17 /* mcs14+shortGI index */
+ #define sg15 16 /* mcs15+shortGI index */
+#endif
+
+UCHAR RateSwitchTableAdapt11N2S[] = {
+/* item no. mcs highPERThrd upMcs3 upMcs1
+ mode lowPERThrd downMcs upMcs2
+*/
+ 22, 15, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x21, 0, 30, 50, 21, 1, 8, 1, 7,/* mcs0 */
+ 1, 0x21, 1, 20, 50, 0, 16, 9, 2, 13,/* mcs1 */
+ 2, 0x21, 2, 20, 50, 1, 17, 9, 3, 20,/* mcs2 */
+ 3, 0x21, 3, 15, 50, 2, 17, 10, 4, 26,/* mcs3 */
+ 4, 0x21, 4, 15, 30, 3, 18, 11, 5, 39,/* mcs4 */
+ 5, 0x21, 5, 10, 25, 4, 18, 12, 6, 52,/* mcs5 */
+ 6, 0x21, 6, 8, 14, 5, 19, 12, 7, 59,/* mcs6 */
+#ifdef SUPPORT_SHORT_GI_RA
+ 7, 0x21, 7, 8, 14, 6, 19, 12, sg07, 65,/* mcs7 */
+#else
+ 7, 0x21, 7, 8, 14, 6, 19, 12, 7, 65,/* mcs7 */
+#endif
+ 8, 0x20, 8, 30, 50, 0, 16, 9, 2, 13,/* mcs8 */
+ 9, 0x20, 9, 20, 50, 8, 17, 10, 4, 26,/* mcs9 */
+ 10, 0x20, 10, 20, 40, 9, 18, 11, 5, 39,/* mcs10 */
+ 11, 0x20, 11, 15, 30, 10, 18, 12, 6, 52,/* mcs11 */
+ 12, 0x20, 12, 15, 30, 11, 20, 13, 12, 78,/* mcs12 */
+ 13, 0x20, 13, 8, 20, 12, 20, 14, 13, 104,/* mcs13 */
+#ifdef SUPPORT_SHORT_GI_RA
+ 14, 0x20, 14, 8, 18, 13, 21, 15,sg14, 117,/* mcs14 */
+ 15, 0x20, 15, 8, 25, 14, 21,sg15,sg14, 130,/* mcs15 */
+ 16, 0x22, 15, 8, 25, 15, 21,sg15,sg15, 144,/* mcs15+shortGI */
+
+ 17, 0x22, 14, 8, 14, 14, 21,sg15, 15, 130, /* mcs14+shortGI */
+ 18, 0x23, 7, 8, 14, 7, 19, 12,sg07, 72, /* mcs7+shortGI */
+#else
+ 14, 0x20, 14, 8, 18, 13, 21, 15, 14, 117,/* mcs14 */
+ 15, 0x20, 15, 8, 25, 14, 21, 16, 15, 130,/* mcs15 */
+ 16, 0x22, 15, 8, 25, 15, 21, 16, 16, 144,/* mcs15+shortGI */
+ 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 18, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ 19, 0x00, 0, 40, 101, 19 , 19, 19, 20, 1, /* cck-1M */
+ 20, 0x00, 1, 40, 50, 19, 20, 20, 21, 2, /* cck-2M */
+ 21, 0x21, 32, 30, 50, 20, 0, 8, 0, 7, /* mcs32 or 20M/mcs0 */
+};
+
+#ifdef SUPPORT_SHORT_GI_RA
+/* Indices for Short GI rates in 11N3S table */
+ #undef sg07
+ #undef sg14
+ #undef sg15
+ #define sg07 29 /* mcs7+shortGI index */
+ #define sg14 27 /* mcs14+shortGI index */
+ #define sg15 28 /* mcs15+shortGI index */
+ #define sg21 25 /* mcs21+shortGI index */
+ #define sg22 26 /* mcs22+shortGI index */
+ #define sg23 24 /* mcs23+shortGI index */
+#endif
+
+UCHAR RateSwitchTableAdapt11N3S[] = {
+/* item no mcs highPERThrd upMcs3 upMcs1
+ mode lowPERThrd downMcs upMcs2
+*/
+ 33, 23, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x21, 0, 30, 50, 32, 1, 8, 1, 7, /* mcs0 */
+ 1, 0x21, 1, 20, 50, 0, 16, 9, 2, 13, /* mcs1 */
+ 2, 0x21, 2, 20, 50, 1, 17, 9, 3, 20, /* mcs2 */
+ 3, 0x21, 3, 15, 50, 2, 17, 10, 4, 26, /* mcs3 */
+ 4, 0x21, 4, 15, 30, 3, 18, 11, 5, 39, /* mcs4 */
+ 5, 0x21, 5, 10, 25, 4, 18, 12, 6, 52, /* mcs5 */
+ 6, 0x21, 6, 8, 14, 5, 19, 12, 7, 59, /* mcs6 */
+#ifdef SUPPORT_SHORT_GI_RA
+ 7, 0x21, 7, 8, 14, 6, 19, 12, sg07, 65, /* mcs7 */
+#else
+ 7, 0x21, 7, 8, 14, 6, 19, 12, 7, 65, /* mcs7 */
+#endif
+ 8, 0x20, 8, 30, 50, 0, 16, 9, 2, 13, /* mcs8 */
+ 9, 0x20, 9, 20, 50, 8, 17, 10, 4, 26, /* mcs9 */
+ 10, 0x20, 10, 20, 40, 9, 18, 11, 5, 39, /* mcs10 */
+ 11, 0x20, 11, 15, 30, 10, 18, 12, 6, 52, /* mcs11 */
+ 12, 0x20, 12, 15, 30, 11, 20, 13, 12, 78, /* mcs12 */
+ 13, 0x20, 13, 8, 20, 12, 20, 14, 13, 104, /* mcs13 */
+#ifdef SUPPORT_SHORT_GI_RA
+ 14, 0x20, 14, 8, 18, 13, 21, 15, sg14, 117, /* mcs14 */
+ 15, 0x20, 15, 8, 14, 14, 21, sg15, sg14, 130, /* mcs15 */
+#else
+ 14, 0x20, 14, 8, 18, 13, 21, 15, 14, 117, /* mcs14 */
+ 15, 0x20, 15, 8, 14, 14, 21, 15, 15, 130, /* mcs15 */
+#endif
+ 16, 0x20, 16, 30, 50, 8, 17, 9, 3, 20, /* mcs16 */
+ 17, 0x20, 17, 20, 50, 16, 18, 11, 5, 39, /* mcs17 */
+ 18, 0x20, 18, 20, 40, 17, 19, 12, 7, 59, /* mcs18 */
+ 19, 0x20, 19, 15, 30, 18, 20, 13, 19, 78, /* mcs19 */
+ 20, 0x20, 20, 15, 30, 19, 21, 15, 20, 117, /* mcs20 */
+#ifdef SUPPORT_SHORT_GI_RA
+ 21, 0x20, 21, 8, 20, 20, 22, sg21, 21, 156, /* mcs21 */
+ 22, 0x20, 22, 8, 20, 21, 23, sg22, sg21, 176, /* mcs22 */
+ 23, 0x20, 23, 6, 18, 22, sg23, 23, sg22, 195, /* mcs23 */
+ 24, 0x22, 23, 6, 14, 23, sg23, sg23, sg23, 217, /* mcs23+shortGI */
+
+ 25, 0x22, 21, 6, 18, 21, sg22, 22, sg21, 173, /* mcs21+shortGI */
+ 26, 0x22, 22, 6, 18, 22, sg23, 23, sg22, 195, /* mcs22+shortGI */
+ 27, 0x22, 14, 8, 14, 14, 21, sg15, 15, 130, /* mcs14+shortGI */
+ 28, 0x22, 15, 8, 14, 15, 21, sg15, sg15, 144, /* mcs15+shortGI */
+ 29, 0x23, 7, 8, 14, 7, 19, 12, 29, 72, /* mcs7+shortGI */
+#else
+ 21, 0x20, 21, 8, 20, 20, 22, 21, 21, 156, /* mcs21 */
+ 22, 0x20, 22, 8, 20, 21, 23, 22, 22, 176, /* mcs22 */
+ 23, 0x20, 23, 6, 18, 22, 24, 23, 23, 195, /* mcs23 */
+ 24, 0x22, 23, 6, 14, 23, 24, 24, 24, 217, /* mcs23+shortGI */
+ 25, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 26, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 27, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 28, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 29, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ 30, 0x00, 0, 40, 101, 30 , 30, 30, 31, 1, /* cck-1M */
+ 31, 0x00, 1, 40, 50, 30, 31, 31, 32, 2, /* cck-2M */
+ 32, 0x21, 32, 30, 50, 31, 0, 8, 0, 7, /* mcs32 or 20M/mcs0 */
+};
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+
+#endif /* DOT11_N_SUPPORT */
+
+
+/* MlmeGetSupportedMcs - fills in the table of mcs with index into the pTable
+ pAd - pointer to adapter
+ pTable - pointer to the Rate Table. Assumed to be a table without mcsGroup values
+ mcs - table of MCS index into the Rate Table. -1 => not supported
+*/
+VOID MlmeGetSupportedMcs(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR *pTable,
+ OUT CHAR mcs[])
+{
+ CHAR idx;
+ PRTMP_TX_RATE_SWITCH pCurrTxRate;
+
+ for (idx=0; idx<24; idx++)
+ mcs[idx] = -1;
+
+ /* check the existence and index of each needed MCS */
+ for (idx=0; idx<RATE_TABLE_SIZE(pTable); idx++)
+ {
+ pCurrTxRate = PTX_RATE_SWITCH_ENTRY(pTable, idx);
+
+ /* Rate Table may contain CCK and MCS rates. Give HT/Legacy priority over CCK */
+ if (pCurrTxRate->CurrMCS==MCS_0 && (mcs[0]==-1 || pCurrTxRate->Mode!=MODE_CCK))
+ {
+ mcs[0] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS==MCS_1 && (mcs[1]==-1 || pCurrTxRate->Mode!=MODE_CCK))
+ {
+ mcs[1] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS==MCS_2 && (mcs[2]==-1 || pCurrTxRate->Mode!=MODE_CCK))
+ {
+ mcs[2] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_3)
+ {
+ mcs[3] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_4)
+ {
+ mcs[4] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_5)
+ {
+ mcs[5] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_6)
+ {
+ mcs[6] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[7] = idx;
+ }
+#ifdef DOT11_N_SUPPORT
+ else if (pCurrTxRate->CurrMCS == MCS_12)
+ {
+ mcs[12] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_13)
+ {
+ mcs[13] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_14)
+ {
+ mcs[14] = idx;
+ }
+ else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800))
+ {
+ mcs[15] = idx;
+ }
+#ifdef DOT11N_SS3_SUPPORT
+ else if (pCurrTxRate->CurrMCS == MCS_20)
+ {
+ mcs[20] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_21)
+ {
+ mcs[21] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_22)
+ {
+ mcs[22] = idx;
+ }
+ else if (pCurrTxRate->CurrMCS == MCS_23)
+ {
+ mcs[23] = idx;
+ }
+#endif /* DOT11N_SS3_SUPPORT */
+#endif /* DOT11_N_SUPPORT */
+ }
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug Option: Disable highest MCSs when picking initial MCS based on RSSI */
+ if (pAd->CommonCfg.DebugFlags & DBF_INIT_MCS_DIS1)
+ mcs[23] = mcs[15] = mcs[7] = mcs[22] = mcs[14] = mcs[6] = 0;
+#endif /* DBG_CTRL_SUPPORT */
+}
+
+
+
+/* MlmeClearTxQuality - Clear TxQuality history only for the active BF state */
+VOID MlmeClearTxQuality(
+ IN MAC_TABLE_ENTRY *pEntry)
+{
+#ifdef TXBF_SUPPORT
+ if (pEntry->phyETxBf || pEntry->phyITxBf)
+ NdisZeroMemory(pEntry->BfTxQuality, sizeof(pEntry->BfTxQuality));
+ else
+#endif /* TXBF_SUPPORT */
+ NdisZeroMemory(pEntry->TxQuality, sizeof(pEntry->TxQuality));
+
+ NdisZeroMemory(pEntry->PER, sizeof(pEntry->PER));
+}
+
+/* MlmeClearAllTxQuality - Clear both BF and non-BF TxQuality history */
+VOID MlmeClearAllTxQuality(
+ IN MAC_TABLE_ENTRY *pEntry)
+{
+#ifdef TXBF_SUPPORT
+ NdisZeroMemory(pEntry->BfTxQuality, sizeof(pEntry->BfTxQuality));
+#endif
+ NdisZeroMemory(pEntry->TxQuality, sizeof(pEntry->TxQuality));
+
+ NdisZeroMemory(pEntry->PER, sizeof(pEntry->PER));
+}
+
+/* MlmeDecTxQuality - Decrement TxQuality of specified rate table entry */
+VOID MlmeDecTxQuality(
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN UCHAR rateIndex)
+{
+#ifdef TXBF_SUPPORT
+ if (pEntry->phyETxBf || pEntry->phyITxBf) {
+ if (pEntry->BfTxQuality[rateIndex])
+ pEntry->BfTxQuality[rateIndex]--;
+ }
+ else
+#endif /* TXBF_SUPPORT */
+ if (pEntry->TxQuality[rateIndex])
+ pEntry->TxQuality[rateIndex]--;
+}
+
+VOID MlmeSetTxQuality(
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN UCHAR rateIndex,
+ IN USHORT txQuality)
+{
+#ifdef TXBF_SUPPORT
+ if (pEntry->phyETxBf || pEntry->phyITxBf)
+ pEntry->BfTxQuality[rateIndex] = txQuality;
+ else
+#endif /* TXBF_SUPPORT */
+ pEntry->TxQuality[rateIndex] = txQuality;
+}
+
+
+USHORT MlmeGetTxQuality(
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN UCHAR rateIndex)
+{
+#ifdef TXBF_SUPPORT
+ if (pEntry->phyETxBf || pEntry->phyITxBf)
+ return pEntry->BfTxQuality[rateIndex];
+#endif /* TXBF_SUPPORT */
+ return pEntry->TxQuality[rateIndex];
+}
+
+
+#ifdef CONFIG_AP_SUPPORT
+VOID APMlmeSetTxRate(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PRTMP_TX_RATE_SWITCH pTxRate)
+{
+#ifdef DOT11_N_SUPPORT
+ if ((pTxRate->STBC) && (pEntry->MaxHTPhyMode.field.STBC))
+ pEntry->HTPhyMode.field.STBC = STBC_USE;
+ else
+ pEntry->HTPhyMode.field.STBC = STBC_NONE;
+
+ if (((pTxRate->ShortGI) && (pEntry->MaxHTPhyMode.field.ShortGI))
+ || (pAd->WIFItestbed.bShortGI && pEntry->MaxHTPhyMode.field.ShortGI) )
+ pEntry->HTPhyMode.field.ShortGI = GI_400;
+ else
+ pEntry->HTPhyMode.field.ShortGI = GI_800;
+#endif /* DOT11_N_SUPPORT */
+
+ if (pTxRate->CurrMCS < MCS_AUTO)
+ pEntry->HTPhyMode.field.MCS = pTxRate->CurrMCS;
+
+ pEntry->HTPhyMode.field.MODE = pTxRate->Mode;
+
+#ifdef DOT11_N_SUPPORT
+ if ((pAd->WIFItestbed.bGreenField & pEntry->HTCapability.HtCapInfo.GF) && (pEntry->HTPhyMode.field.MODE == MODE_HTMIX))
+ {
+ /* force Tx GreenField */
+ pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD;
+ }
+
+ /* BW depends on BSSWidthTrigger and Negotiated BW */
+ if (pAd->CommonCfg.bRcvBSSWidthTriggerEvents ||
+ (pEntry->MaxHTPhyMode.field.BW==BW_20) ||
+ (pAd->CommonCfg.BBPCurrentBW==BW_20))
+ pEntry->HTPhyMode.field.BW = BW_20;
+ else
+ pEntry->HTPhyMode.field.BW = BW_40;
+
+#ifdef RANGE_EXTEND
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ /* 20 MHz Fallback */
+ if (pTxRate->Mode >= MODE_HTMIX &&
+ pEntry->HTPhyMode.field.BW == BW_40 &&
+ ADAPT_RATE_TABLE(pEntry->pTable))
+ {
+ if (pEntry->HTPhyMode.field.MCS==32
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_DISABLE_20MHZ_MCS0)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ /* Map HT Duplicate to 20MHz MCS0 */
+ pEntry->HTPhyMode.field.BW = BW_20;
+ pEntry->HTPhyMode.field.MCS = 0;
+ }
+ else if (pEntry->HTPhyMode.field.MCS==0 &&
+ (pAd->CommonCfg.DebugFlags & DBF_FORCE_20MHZ)==0
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_DISABLE_20MHZ_MCS1)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ /* Map 40MHz MCS0 to 20MHz MCS1 */
+ pEntry->HTPhyMode.field.BW = BW_20;
+ pEntry->HTPhyMode.field.MCS = 1;
+ }
+ else if (pEntry->HTPhyMode.field.MCS==8
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_ENABLE_20MHZ_MCS8)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ /* Map 40MHz MCS8 to 20MHz MCS8 */
+ pEntry->HTPhyMode.field.BW = BW_20;
+ }
+ }
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug Option: Force BW */
+ if (pAd->CommonCfg.DebugFlags & DBF_FORCE_40MHZ)
+ {
+ pEntry->HTPhyMode.field.BW = BW_40;
+ }
+ else if (pAd->CommonCfg.DebugFlags & DBF_FORCE_20MHZ)
+ {
+ pEntry->HTPhyMode.field.BW = BW_20;
+ }
+#endif /* DBG_CTRL_SUPPORT */
+#endif /* RANGE_EXTEND */
+
+ /* Reexam each bandwidth's SGI support. */
+ if ((pEntry->HTPhyMode.field.BW==BW_20 && !CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE)) ||
+ (pEntry->HTPhyMode.field.BW==BW_40 && !CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE)) )
+ pEntry->HTPhyMode.field.ShortGI = GI_800;
+
+#ifdef DBG_CTRL_SUPPORT
+ /* Debug option: Force Short GI */
+ if (pAd->CommonCfg.DebugFlags & DBF_FORCE_SGI)
+ pEntry->HTPhyMode.field.ShortGI = GI_400;
+#endif /* DBG_CTRL_SUPPORT */
+#endif /* DOT11_N_SUPPORT */
+
+ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word);
+
+#ifdef FIFO_EXT_SUPPORT
+ AsicFifoExtEntryClean(pAd, pEntry);
+#endif /* FIFO_EXT_SUPPORT */
+
+
+
+}
+#endif /* CONFIG_AP_SUPPORT */
+
+
+
+
+VOID MlmeSelectTxRateTable(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PUCHAR *ppTable,
+ IN PUCHAR pTableSize,
+ IN PUCHAR pInitTxRateIdx)
+{
+ do
+ {
+ /* decide the rate table for tuning*/
+ if (pAd->CommonCfg.TxRateTableSize > 0)
+ {
+ *ppTable = RateSwitchTable;
+ break;
+ }
+
+
+#ifdef DOT11_N_SUPPORT
+ /*if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) &&*/
+ /* ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1)))*/
+ if ((pEntry->SupportRateMode & (SUPPORT_OFDM_MODE)) &&
+ (pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1)))
+ {/* 11BGN 1S AP*/
+#ifdef AGS_SUPPORT
+ if (SUPPORT_AGS(pAd))
+ *ppTable = AGS1x1HTRateTable;
+ else
+#endif /* AGS_SUPPORT */
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N1S;
+ else
+#endif
+ if ((pAd->LatchRfRegs.Channel <= 14) && (pEntry->SupportRateMode & (SUPPORT_CCK_MODE)))
+ *ppTable = RateSwitchTable11BGN1S;
+ else
+ *ppTable = RateSwitchTable11N1SForABand;
+
+ break;
+ }
+
+#ifdef AGS_SUPPORT
+ /* only for station */
+ if (SUPPORT_AGS(pAd) &&
+ (pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[1] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[2] != 0x00) &&
+ (pAd->CommonCfg.TxStream == 3))
+ {/* 11N 3S */
+ *ppTable = AGS3x3HTRateTable;
+ break;
+ }
+#endif /* AGS_SUPPORT */
+
+ /*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) &&*/
+ /* (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2))*/
+ if ((pEntry->SupportRateMode & (SUPPORT_OFDM_MODE)) &&
+ (pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[1] != 0x00) &&
+ (((pAd->Antenna.field.TxPath == 3) && (pEntry->HTCapability.MCSSet[2] == 0x00)) || (pAd->CommonCfg.TxStream == 2)))
+ {/* 11BGN 2S AP*/
+#ifdef AGS_SUPPORT
+ if (SUPPORT_AGS(pAd))
+ {
+ *ppTable = AGS2x2HTRateTable;
+ }
+ else
+#endif /* AGS_SUPPORT */
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N2S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if ((pAd->LatchRfRegs.Channel <= 14) && (pEntry->SupportRateMode & (SUPPORT_CCK_MODE)))
+ *ppTable = RateSwitchTable11BGN2S;
+ else
+ *ppTable = RateSwitchTable11BGN2SForABand;
+
+ break;
+ }
+
+#ifdef DOT11N_SS3_SUPPORT
+ if ((pEntry->SupportRateMode & (SUPPORT_OFDM_MODE)) &&
+ (pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[1] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[2] != 0x00) &&
+ (pAd->CommonCfg.TxStream == 3))
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ {
+ *ppTable = RateSwitchTableAdapt11N3S;
+ }
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if ((pAd->LatchRfRegs.Channel <= 14) && (pEntry->SupportRateMode & (SUPPORT_CCK_MODE)))
+ *ppTable = RateSwitchTable11N3S;
+ else
+ *ppTable = RateSwitchTable11N3SForABand;
+
+ break;
+ }
+#endif /* DOT11N_SS3_SUPPORT */
+
+ /*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1)))*/
+ if ((pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1)))
+ {/* 11N 1S AP*/
+#ifdef AGS_SUPPORT
+ if (SUPPORT_AGS(pAd))
+ *ppTable = AGS1x1HTRateTable;
+ else
+#endif /* AGS_SUPPORT */
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N1S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if (pAd->LatchRfRegs.Channel <= 14)
+ *ppTable = RateSwitchTable11N1S;
+ else
+ *ppTable = RateSwitchTable11N1SForABand;
+ }
+ break;
+ }
+
+ /*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2))*/
+ if ((pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[1] != 0x00) &&
+ (pAd->CommonCfg.TxStream == 2))
+ {/* 11N 2S AP*/
+#ifdef AGS_SUPPORT
+ if (SUPPORT_AGS(pAd))
+ *ppTable = AGS2x2HTRateTable;
+ else
+#endif /* AGS_SUPPORT */
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N2S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if (pAd->LatchRfRegs.Channel <= 14)
+ *ppTable = RateSwitchTable11N2S;
+ else
+ *ppTable = RateSwitchTable11N2SForABand;
+ }
+ break;
+ }
+
+#ifdef DOT11N_SS3_SUPPORT
+ if ((pEntry->HTCapability.MCSSet[0] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[1] != 0x00) &&
+ (pEntry->HTCapability.MCSSet[2] != 0x00) &&
+ (pAd->CommonCfg.TxStream == 3))
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N3S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ {
+ if (pAd->LatchRfRegs.Channel <= 14)
+ *ppTable = RateSwitchTable11N3S;
+ else
+ *ppTable = RateSwitchTable11N3SForABand;
+ }
+ break;
+ }
+#endif /* DOT11N_SS3_SUPPORT */
+
+#ifdef DOT11N_SS3_SUPPORT
+ if (pAd->CommonCfg.TxStream == 3)
+ {
+ if (pEntry->HTCapability.MCSSet[0] != 0x00)
+ {
+ if (pEntry->HTCapability.MCSSet[1] == 0x00)
+ { /* Only support 1SS */
+ if (pEntry->RateLen > 0)
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N1S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if ((pAd->LatchRfRegs.Channel <= 14) && (pEntry->SupportRateMode & (SUPPORT_CCK_MODE)))
+ *ppTable = RateSwitchTable11N1S;
+ else
+ *ppTable = RateSwitchTable11N1SForABand;
+ }
+ else
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N1S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if (pAd->LatchRfRegs.Channel <= 14)
+ *ppTable = RateSwitchTable11N1S;
+ else
+ *ppTable = RateSwitchTable11N1SForABand;
+ }
+ break;
+ }
+ else if (pEntry->HTCapability.MCSSet[2] == 0x00)
+ { /* Only support 2SS */
+ if (pEntry->RateLen > 0)
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N2S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if ((pAd->LatchRfRegs.Channel <= 14) && (pEntry->SupportRateMode & (SUPPORT_CCK_MODE)))
+ *ppTable = RateSwitchTable11BGN2S;
+ else
+ *ppTable = RateSwitchTable11BGN2SForABand;
+ }
+ else
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ *ppTable = RateSwitchTableAdapt11N2S;
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ if (pAd->LatchRfRegs.Channel <= 14)
+ *ppTable = RateSwitchTable11N2S;
+ else
+ *ppTable = RateSwitchTable11N2SForABand;
+ }
+ break;
+ }
+ /* For 3SS case, we use the new rate table, so don't care it here */
+ }
+ }
+#endif /* DOT11N_SS3_SUPPORT */
+#endif /* DOT11_N_SUPPORT */
+
+ if (((pEntry->SupportRateMode == SUPPORT_CCK_MODE) || pAd->CommonCfg.PhyMode==PHY_11B)
+#ifdef DOT11_N_SUPPORT
+ /*Iverson mark for Adhoc b mode,sta will use rate 54 Mbps when connect with sta b/g/n mode */
+ /* && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)*/
+#endif /* DOT11_N_SUPPORT */
+ )
+ {/* B only AP*/
+ *ppTable = RateSwitchTable11B;
+ break;
+ }
+
+ /*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0))*/
+ if ((pEntry->SupportRateMode & (SUPPORT_CCK_MODE)) &&
+ (pEntry->SupportRateMode & (SUPPORT_OFDM_MODE))
+#ifdef DOT11_N_SUPPORT
+ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
+#endif /* DOT11_N_SUPPORT */
+ )
+ {/* B/G mixed AP*/
+ *ppTable = RateSwitchTable11BG;
+ break;
+ }
+
+ /*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0))*/
+ if ((pEntry->SupportRateMode & (SUPPORT_OFDM_MODE))
+#ifdef DOT11_N_SUPPORT
+ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
+#endif /* DOT11_N_SUPPORT */
+ )
+ {/* G only AP*/
+ *ppTable = RateSwitchTable11G;
+ break;
+ }
+#ifdef DOT11_N_SUPPORT
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef DOT11N_SS3_SUPPORT
+ if (pAd->CommonCfg.TxStream >= 3)
+ {
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (pAd->rateAlg == RATE_ALG_GRP)
+ {
+ if (pEntry->HTCapability.MCSSet[2] == 0)
+ *ppTable = RateSwitchTableAdapt11N2S;
+ else
+ *ppTable = RateSwitchTableAdapt11N3S;
+ }
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ {
+ if (pEntry->HTCapability.MCSSet[2] == 0)
+ *ppTable = RateSwitchTable11N2S;
+ else
+ *ppTable = RateSwitchTable11N3S;
+ }
+ }
+ else
+#endif /* DOT11N_SS3_SUPPORT */
+ {
+ /*
+ Temp solution for:
+ EX: when the extend rate only supports 6, 12, 24 in
+ the association req frame. So the pEntry->RateLen is 7.
+ */
+ if (pAd->LatchRfRegs.Channel <= 14)
+ *ppTable = RateSwitchTable11BG;
+ else
+ *ppTable = RateSwitchTable11G;
+ }
+ break;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+#endif /* DOT11_N_SUPPORT */
+
+ } while(FALSE);
+
+ *pTableSize = RATE_TABLE_SIZE(*ppTable);
+ *pInitTxRateIdx = RATE_TABLE_INIT_INDEX(*ppTable);
+
+}
+
+
+
+/*
+ MlmeSelectTxRate - select the MCS based on the RSSI and the available MCSs
+ pAd - pointer to adapter
+ pEntry - pointer to MAC table entry
+ mcs - table of MCS index into the Rate Table. -1 => not supported
+ Rssi - the Rssi value
+ RssiOffset - offset to apply to the Rssi
+*/
+UCHAR MlmeSelectTxRate(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN CHAR mcs[],
+ IN CHAR Rssi,
+ IN CHAR RssiOffset)
+{
+ UCHAR TxRateIdx = 0;
+ UCHAR *pTable = pEntry->pTable;
+
+#ifdef DOT11_N_SUPPORT
+#ifdef DOT11N_SS3_SUPPORT
+ if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || (pTable == RateSwitchTable11BGN3SForABand)
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ || (pTable == RateSwitchTableAdapt11N3S)
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ )
+ {/* N mode with 3 stream */
+ if (mcs[23]>=0 && (Rssi >= (-66+RssiOffset)) && (pEntry->SupportHTMCS[MCS_23]))
+ TxRateIdx = mcs[23];
+ else if (mcs[22]>=0 && (Rssi >= (-70+RssiOffset)) && (pEntry->SupportHTMCS[MCS_22]))
+ TxRateIdx = mcs[22];
+ else if (mcs[21]>=0 && (Rssi >= (-72+RssiOffset)) && (pEntry->SupportHTMCS[MCS_21]))
+ TxRateIdx = mcs[21];
+ else if (mcs[20]>=0 && (Rssi >= (-74+RssiOffset)) && (pEntry->SupportHTMCS[MCS_20]))
+ TxRateIdx = mcs[20];
+ else if (mcs[13]>=0 && (Rssi >= (-76+RssiOffset)) && (pEntry->SupportHTMCS[MCS_13]))
+ TxRateIdx = mcs[13];
+ else if (mcs[12]>=0 && (Rssi >= (-78+RssiOffset)) && (pEntry->SupportHTMCS[MCS_12]))
+ TxRateIdx = mcs[12];
+ else if (mcs[4]>=0 && (Rssi >= (-82+RssiOffset)) && (pEntry->SupportHTMCS[MCS_4]))
+ TxRateIdx = mcs[4];
+ else if (mcs[3]>=0 && (Rssi >= (-84+RssiOffset)) && (pEntry->SupportHTMCS[MCS_3]))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi >= (-86+RssiOffset)) && (pEntry->SupportHTMCS[MCS_2]))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi >= (-88+RssiOffset)) && (pEntry->SupportHTMCS[MCS_1]))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+ else
+#endif /* DOT11N_SS3_SUPPORT */
+ if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||
+ (pTable == RateSwitchTable11N2S) || (pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ || (pTable == RateSwitchTableAdapt11N2S)
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ )
+ {/* N mode with 2 stream */
+ if (mcs[15]>=0 && (Rssi >= (-70+RssiOffset)) && (pEntry->SupportHTMCS[MCS_15]))
+ TxRateIdx = mcs[15];
+ else if (mcs[14]>=0 && (Rssi >= (-72+RssiOffset)) && (pEntry->SupportHTMCS[MCS_14]))
+ TxRateIdx = mcs[14];
+ else if (mcs[13]>=0 && (Rssi >= (-76+RssiOffset)) && (pEntry->SupportHTMCS[MCS_13]))
+ TxRateIdx = mcs[13];
+ else if (mcs[12]>=0 && (Rssi >= (-78+RssiOffset)) && (pEntry->SupportHTMCS[MCS_12]))
+ TxRateIdx = mcs[12];
+ else if (mcs[4]>=0 && (Rssi >= (-82+RssiOffset)) && (pEntry->SupportHTMCS[MCS_4]))
+ TxRateIdx = mcs[4];
+ else if (mcs[3]>=0 && (Rssi >= (-84+RssiOffset)) && (pEntry->SupportHTMCS[MCS_3]))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi >= (-86+RssiOffset)) && (pEntry->SupportHTMCS[MCS_2]))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi >= (-88+RssiOffset)) && (pEntry->SupportHTMCS[MCS_1]))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+ else if ((pTable == RateSwitchTable11BGN1S) ||
+ (pTable == RateSwitchTable11N1S) ||
+ (pTable == RateSwitchTable11N1SForABand)
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ || (pTable == RateSwitchTableAdapt11N1S)
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ )
+ {/* N mode with 1 stream */
+ if (mcs[7]>=0 && (Rssi > (-72+RssiOffset)) && (pEntry->SupportHTMCS[MCS_7]))
+ TxRateIdx = mcs[7];
+ else if (mcs[6]>=0 && (Rssi > (-74+RssiOffset)) && (pEntry->SupportHTMCS[MCS_6]))
+ TxRateIdx = mcs[6];
+ else if (mcs[5]>=0 && (Rssi > (-77+RssiOffset)) && (pEntry->SupportHTMCS[MCS_5]))
+ TxRateIdx = mcs[5];
+ else if (mcs[4]>=0 && (Rssi > (-79+RssiOffset)) && (pEntry->SupportHTMCS[MCS_4]))
+ TxRateIdx = mcs[4];
+ else if (mcs[3]>=0 && (Rssi > (-81+RssiOffset)) && (pEntry->SupportHTMCS[MCS_3]))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi > (-83+RssiOffset)) && (pEntry->SupportHTMCS[MCS_2]))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > (-86+RssiOffset)) && (pEntry->SupportHTMCS[MCS_1]))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+ else
+#endif /* DOT11_N_SUPPORT */
+ {/* Legacy mode */
+ if (mcs[7]>=0 && (Rssi > -70) && (pEntry->SupportOFDMMCS[MCS_7]))
+ TxRateIdx = mcs[7];
+ else if (mcs[6]>=0 && (Rssi > -74) && (pEntry->SupportOFDMMCS[MCS_7]))
+ TxRateIdx = mcs[6];
+ else if (mcs[5]>=0 && (Rssi > -78) && (pEntry->SupportOFDMMCS[MCS_7]))
+ TxRateIdx = mcs[5];
+ else if (mcs[4]>=0 && (Rssi > -82) && (pEntry->SupportOFDMMCS[MCS_7]))
+ TxRateIdx = mcs[4];
+ else if (mcs[4] == -1) /* for B-only mode */
+ {
+ if (mcs[3]>=0 && (Rssi > -85) && (pEntry->SupportCCKMCS[MCS_3]))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi > -87) && (pEntry->SupportCCKMCS[MCS_2]))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > -90) && (pEntry->SupportCCKMCS[MCS_1]))
+ TxRateIdx = mcs[1];
+ else if (pEntry->SupportCCKMCS[MCS_0])
+ TxRateIdx = mcs[0];
+ else
+ TxRateIdx = mcs[3];
+ }
+ else if (mcs[3]>=0 && (Rssi > -85) && (pEntry->SupportOFDMMCS[MCS_3]))
+ TxRateIdx = mcs[3];
+ else if (mcs[2]>=0 && (Rssi > -87) && (pEntry->SupportOFDMMCS[MCS_2]))
+ TxRateIdx = mcs[2];
+ else if (mcs[1]>=0 && (Rssi > -90) && (pEntry->SupportOFDMMCS[MCS_1]))
+ TxRateIdx = mcs[1];
+ else
+ TxRateIdx = mcs[0];
+ }
+
+ return TxRateIdx;
+}
+
+
+/* MlmeRAInit - Initialize Rate Adaptation for this entry */
+VOID MlmeRAInit(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry)
+{
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ MlmeSetMcsGroup(pAd, pEntry);
+
+ pEntry->lastRateIdx = 1;
+ pEntry->lowTrafficCount = 0;
+ pEntry->perThrdAdj = PER_THRD_ADJ;
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+
+#ifdef TXBF_SUPPORT
+ pEntry->phyETxBf = pEntry->phyITxBf = FALSE;
+ pEntry->lastRatePhyTxBf = FALSE;
+ pEntry->lastNonBfRate = 0;
+#endif /* TXBF_SUPPORT */
+
+ pEntry->fLastSecAccordingRSSI = FALSE;
+ pEntry->LastSecTxRateChangeAction = RATE_NO_CHANGE;
+ pEntry->CurrTxRateIndex = 0;
+ pEntry->CurrTxRateStableTime = 0;
+ pEntry->TxRateUpPenalty = 0;
+
+ MlmeClearAllTxQuality(pEntry);
+}
+
+
+/* #define TIMESTAMP_RA_LOG */ /* Include timestamp in RA Log */
+
+/*
+ MlmeRALog - Prints concise Rate Adaptation log entry
+ The BF percentage counters are also updated
+*/
+VOID MlmeRALog(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN RA_LOG_TYPE raLogType,
+ IN ULONG TxErrorRatio,
+ IN ULONG TxTotalCnt)
+{
+#ifdef TXBF_SUPPORT
+ UINT ETxCount = pEntry->TxBFCounters.ETxSuccessCount + pEntry->TxBFCounters.ETxFailCount;
+ UINT ITxCount = pEntry->TxBFCounters.ITxSuccessCount + pEntry->TxBFCounters.ITxFailCount;
+ UINT TxCount = pEntry->TxBFCounters.TxSuccessCount + pEntry->TxBFCounters.TxFailCount + ETxCount + ITxCount;
+ ULONG bfRatio = 0;
+#endif /* TXBF_SUPPORT */
+#ifdef TIMESTAMP_RA_LOG
+ ULONG newTime;
+ static ULONG saveRATime;
+ struct timeval tval;
+
+ do_gettimeofday(&tval);
+ newTime = (tval.tv_sec*1000000L + tval.tv_usec);
+#endif
+
+ if (TxTotalCnt !=0 || raLogType==RAL_QUICK_DRS
+#ifdef DBG_CTRL_SUPPORT
+ || (pAd->CommonCfg.DebugFlags & DBF_SHOW_ZERO_RA_LOG)
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ BOOLEAN stbc, csd=FALSE;
+ ULONG tp;
+
+ /* Get STBC and StreamMode state */
+ stbc = (pEntry->HTPhyMode.field.STBC && pEntry->HTPhyMode.field.MCS<8);
+
+#ifdef STREAM_MODE_SUPPORT
+ if (pEntry->StreamModeMACReg != 0)
+ {
+ ULONG streamWord;
+
+ RTMP_IO_READ32(pAd, pEntry->StreamModeMACReg+4, &streamWord);
+ if (pEntry->HTPhyMode.field.MCS < 8)
+ csd = (streamWord & 0x30000)==0x30000;
+ else if (pEntry->HTPhyMode.field.MCS < 16)
+ csd = (streamWord & 0xC0000)==0xC0000;
+ }
+#endif /* STREAM_MODE_SUPPORT */
+
+ /* Normalized throughput - packets per RA Interval */
+ if (raLogType==RAL_QUICK_DRS)
+ tp = (100-TxErrorRatio)*TxTotalCnt*RA_INTERVAL/(100*DEF_QUICK_RA_TIME_INTERVAL);
+ else if (pEntry->LastSecTxRateChangeAction==RATE_NO_CHANGE
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_FORCE_QUICK_DRS)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ tp = (100-TxErrorRatio)*TxTotalCnt/100;
+ else
+ tp = (100-TxErrorRatio)*TxTotalCnt*RA_INTERVAL/(100*(RA_INTERVAL-DEF_QUICK_RA_TIME_INTERVAL));
+
+#ifdef TXBF_SUPPORT
+ /* Compute BF ratio in the last interval */
+ if ((TxCount - pEntry->LastTxCount)>0)
+ {
+ if (pEntry->HTPhyMode.field.eTxBF)
+ bfRatio = 100*(ETxCount-pEntry->LastETxCount)/(TxCount - pEntry->LastTxCount);
+ else if (pEntry->HTPhyMode.field.iTxBF)
+ bfRatio = 100*(ITxCount-pEntry->LastITxCount)/(TxCount - pEntry->LastTxCount);
+ }
+
+ if ((pEntry->HTPhyMode.field.eTxBF || pEntry->HTPhyMode.field.iTxBF)
+#ifdef DBG_CTRL_SUPPORT
+ && (pAd->CommonCfg.DebugFlags & DBF_DBQ_RA_LOG)==0
+#endif /* DBG_CTRL_SUPPORT */
+ )
+ {
+ DBGPRINT_RAW(RT_DEBUG_ERROR,("%s[%d]: M=%d %c%c%c%c%c PER=%ld%% TP=%ld BF=%ld%% ",
+ raLogType==RAL_QUICK_DRS? " Q": (raLogType==RAL_NEW_DRS? "\nRA": "\nra"),
+ pEntry->Aid, pEntry->HTPhyMode.field.MCS,
+ pEntry->HTPhyMode.field.MODE==MODE_CCK? 'C': (pEntry->HTPhyMode.field.ShortGI? 'S': 'L'),
+ pEntry->HTPhyMode.field.BW? '4': '2',
+ stbc? 'S': 's',
+ csd? 'C': 'c',
+ pEntry->HTPhyMode.field.eTxBF? 'E': (pEntry->HTPhyMode.field.iTxBF? 'I': '-'),
+ TxErrorRatio, tp, bfRatio) );
+ }
+ else
+#endif /* TXBF_SUPPORT */
+#ifdef DBG_CTRL_SUPPORT
+#ifdef INCLUDE_DEBUG_QUEUE
+ if (pAd->CommonCfg.DebugFlags & DBF_DBQ_RA_LOG)
+ {
+ struct {
+ USHORT phyMode;
+ USHORT per;
+ USHORT tp;
+ USHORT bfRatio;
+ } raLogInfo;
+
+ raLogInfo.phyMode = pEntry->HTPhyMode.word;
+ raLogInfo.per = TxErrorRatio;
+ raLogInfo.tp = tp;
+#ifdef TXBF_SUPPORT
+ raLogInfo.bfRatio = bfRatio;
+#endif /* TXBF_SUPPORT */
+ dbQueueEnqueue(0x7e, (UCHAR *)&raLogInfo);
+ }
+ else
+#endif /* INCLUDE_DEBUG_QUEUE */
+#endif /* DBG_CTRL_SUPPORT */
+ {
+ DBGPRINT_RAW(RT_DEBUG_ERROR,("%s[%d]: M=%d %c%c%c%c- PER=%ld%% TP=%ld ",
+ raLogType==RAL_QUICK_DRS? " Q": (raLogType==RAL_NEW_DRS? "\nRA": "\nra"),
+ pEntry->Aid, pEntry->HTPhyMode.field.MCS,
+ pEntry->HTPhyMode.field.MODE==MODE_CCK? 'C': (pEntry->HTPhyMode.field.ShortGI? 'S': 'L'),
+ pEntry->HTPhyMode.field.BW? '4': '2',
+ stbc? 'S': 's',
+ csd? 'C': 'c',
+ TxErrorRatio, tp) );
+ }
+ }
+
+#ifdef TXBF_SUPPORT
+ /* Remember previous counts */
+ pEntry->LastETxCount = ETxCount;
+ pEntry->LastITxCount = ITxCount;
+ pEntry->LastTxCount = TxCount;
+#endif /* TXBF_SUPPORT */
+#ifdef TIMESTAMP_RA_LOG
+ saveRATime = newTime;
+#endif
+}
+
+
+/* MlmeRestoreLastRate - restore last saved rate */
+VOID MlmeRestoreLastRate(
+ IN PMAC_TABLE_ENTRY pEntry)
+{
+ pEntry->CurrTxRateIndex = pEntry->lastRateIdx;
+#ifdef TXBF_SUPPORT
+ if (pEntry->eTxBfEnCond>0)
+ pEntry->phyETxBf = pEntry->lastRatePhyTxBf;
+ else
+ pEntry->phyITxBf = pEntry->lastRatePhyTxBf;
+#endif /* TXBF_SUPPORT */
+}
+
+
+#ifdef DOT11N_SS3_SUPPORT
+/* MlmeCheckRDG - check if RDG should be enabled or disabled */
+VOID MlmeCheckRDG(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry)
+{
+ PUCHAR pTable = pEntry->pTable;
+
+ /* Turn off RDG when 3s and rx count > tx count*5 */
+ if (((pTable == RateSwitchTable11BGN3S) ||
+ (pTable == RateSwitchTable11BGN3SForABand) ||
+ (pTable == RateSwitchTable11N3S)
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ || (pTable == RateSwitchTableAdapt11N3S)
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ ) && pAd->RalinkCounters.OneSecReceivedByteCount > 50000 &&
+ pAd->RalinkCounters.OneSecTransmittedByteCount > 50000 &&
+ CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE))
+ {
+ TX_LINK_CFG_STRUC TxLinkCfg;
+ ULONG TxOpThres;
+ UCHAR TableStep;
+ PRTMP_TX_RATE_SWITCH pTempTxRate;
+
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ TableStep = ADAPT_RATE_TABLE(pTable)? 10: 5;
+#else
+ TableStep = 5;
+#endif
+
+ pTempTxRate = (PRTMP_TX_RATE_SWITCH)(&pTable[(pEntry->CurrTxRateIndex + 1)*TableStep]);
+ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
+
+ if (pAd->RalinkCounters.OneSecReceivedByteCount > (pAd->RalinkCounters.OneSecTransmittedByteCount * 5) &&
+ pTempTxRate->CurrMCS != 23 && pTempTxRate->ShortGI != 1)
+ {
+ if (TxLinkCfg.field.TxRDGEn == 1)
+ {
+ TxLinkCfg.field.TxRDGEn = 0;
+ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
+ RTMP_IO_READ32(pAd, TXOP_THRES_CFG, &TxOpThres);
+ TxOpThres |= 0xff00;
+ RTMP_IO_WRITE32(pAd, TXOP_THRES_CFG, TxOpThres);
+ DBGPRINT_RAW(RT_DEBUG_WARN,("DRS: RDG off!\n"));
+ }
+ }
+ else
+ {
+ if (TxLinkCfg.field.TxRDGEn == 0)
+ {
+ TxLinkCfg.field.TxRDGEn = 1;
+ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
+ RTMP_IO_READ32(pAd, TXOP_THRES_CFG, &TxOpThres);
+ TxOpThres &= 0xffff00ff;
+ RTMP_IO_WRITE32(pAd, TXOP_THRES_CFG, TxOpThres);
+ DBGPRINT_RAW(RT_DEBUG_WARN,("DRS: RDG on!\n"));
+ }
+ }
+ }
+}
+#endif /* DOT11N_SS3_SUPPORT */
+
+
+/*
+ MlmeNewTxRate - called when a new TX rate was selected. Sets TX PHY to
+ rate selected by pEntry->CurrTxRateIndex in pTable;
+*/
+VOID MlmeNewTxRate(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry)
+{
+ PRTMP_TX_RATE_SWITCH pNextTxRate;
+ UCHAR *pTable = pEntry->pTable;
+
+ /* Get pointer to CurrTxRate entry */
+#ifdef NEW_RATE_ADAPT_SUPPORT
+ if (ADAPT_RATE_TABLE(pTable))
+ pNextTxRate = (PRTMP_TX_RATE_SWITCH)PTX_RATE_SWITCH_ENTRY_3S(pTable, pEntry->CurrTxRateIndex);
+ else
+#endif /* NEW_RATE_ADAPT_SUPPORT */
+ pNextTxRate = PTX_RATE_SWITCH_ENTRY(pTable, pEntry->CurrTxRateIndex);
+
+ /* Set new rate */
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ APMlmeSetTxRate(pAd, pEntry, pNextTxRate);
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+#ifdef DOT11_N_SUPPORT
+ /* Disable invalid HT Duplicate modes to prevent PHY error */
+ if (pEntry->HTPhyMode.field.MCS==32)
+ {
+ if (pEntry->HTPhyMode.field.BW!=BW_40)
+ pEntry->HTPhyMode.field.MCS = 0;
+ else
+ pEntry->HTPhyMode.field.STBC = 0;
+ }
+#endif /* DOT11_N_SUPPORT */
+
+#ifdef TXBF_SUPPORT
+ if (pAd->chipCap.FlgHwTxBfCap)
+ {
+ /* If BF has been disabled then force a non-BF rate */
+ if (pEntry->eTxBfEnCond==0)
+ pEntry->phyETxBf = 0;
+
+ if (pEntry->iTxBfEn==0)
+ pEntry->phyITxBf = 0;
+
+
+ /* Set BF options */
+ pEntry->HTPhyMode.field.eTxBF = pEntry->phyETxBf;
+ pEntry->HTPhyMode.field.iTxBF = pEntry->phyITxBf;
+
+ /* Give ETxBF priority over ITxBF */
+ if (pEntry->HTPhyMode.field.eTxBF)
+ pEntry->HTPhyMode.field.iTxBF = 0;
+
+ /* In ITxBF mode force GI if we have no choice */
+ if (pEntry->HTPhyMode.field.iTxBF &&
+ (pEntry->OneSecRxLGICount + pEntry->OneSecRxSGICount) > 10)
+ {
+ if (pEntry->OneSecRxSGICount==0)
+ pEntry->HTPhyMode.field.ShortGI = GI_800;
+
+ if (pEntry->OneSecRxLGICount==0)
+ {
+ if ((pEntry->HTPhyMode.field.BW==BW_20 && CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE)) ||
+ (pEntry->HTPhyMode.field.BW==BW_40 && CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE)))
+ pEntry->HTPhyMode.field.ShortGI = GI_400;
+ }
+ }
+
+ /* Disable STBC if BF is enabled */
+ if (pEntry->HTPhyMode.field.eTxBF || pEntry->HTPhyMode.field.iTxBF)
+ pEntry->HTPhyMode.field.STBC = STBC_NONE;
+ }
+#endif /* TXBF_SUPPORT */
+
+ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word);
+
+#ifdef STREAM_MODE_SUPPORT
+ /* Enable/disable stream mode based on MCS */
+ if (pAd->CommonCfg.StreamMode!=0 &&
+ pEntry->StreamModeMACReg!=0)
+ {
+ UINT streamWord;
+ BOOLEAN mcsDisable;
+
+ /* OFDM: depends on StreamModeMCS, CCK: always applies stream-mode */
+ mcsDisable = (pEntry->HTPhyMode.field.MCS < 16) &&
+ (pAd->CommonCfg.StreamModeMCS & (1<<pEntry->HTPhyMode.field.MCS))==0 &&
+ (pEntry->HTPhyMode.field.MODE != MODE_CCK);
+
+ streamWord = mcsDisable? 0: StreamModeRegVal(pAd);
+
+ /* Update Stream Mode control reg */
+ RTMP_IO_WRITE32(pAd, pEntry->StreamModeMACReg+4, streamWord | (ULONG)(pEntry->Addr[4]) | (ULONG)(pEntry->Addr[5] << 8));
+ }
+#endif /* STREAM_MODE_SUPPORT */
+}
+
+VOID RTMPSetSupportMCS(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR OpMode,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR SupRate[],
+ IN UCHAR SupRateLen,
+ IN UCHAR ExtRate[],
+ IN UCHAR ExtRateLen,
+ IN HT_CAPABILITY_IE *pHtCapability,
+ IN UCHAR HtCapabilityLen)
+{
+ UCHAR idx, SupportedRatesLen = 0;
+ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES];
+
+ if (SupRateLen > 0)
+ {
+ if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
+ {
+ NdisMoveMemory(SupportedRates, SupRate, SupRateLen);
+ SupportedRatesLen = SupRateLen;
+ }
+ else
+ {
+ UCHAR RateDefault[8] = {0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c};
+
+ NdisMoveMemory(SupportedRates, RateDefault, 8);
+ SupportedRatesLen = 8;
+
+ DBGPRINT(RT_DEBUG_TRACE,("RTMPSetSupportMCS - wrong SUPP RATES., Len=%d\n", SupRateLen));
+ }
+ }
+
+ if (ExtRateLen > 0)
+ {
+ if ((SupRateLen + ExtRateLen) <= MAX_LEN_OF_SUPPORTED_RATES)
+ {
+ NdisMoveMemory(&SupportedRates[SupRateLen], ExtRate, ExtRateLen);
+ SupportedRatesLen += ExtRateLen;
+ }
+ else
+ {
+ NdisMoveMemory(&SupportedRates[SupRateLen], ExtRate, MAX_LEN_OF_SUPPORTED_RATES - ExtRateLen);
+ SupportedRatesLen = MAX_LEN_OF_SUPPORTED_RATES;
+
+ }
+ }
+ /* Clear Supported MCS Table */
+ NdisZeroMemory(pEntry->SupportCCKMCS, MAX_LEN_OF_CCK_RATES);
+ NdisZeroMemory(pEntry->SupportOFDMMCS, MAX_LEN_OF_OFDM_RATES);
+ NdisZeroMemory(pEntry->SupportHTMCS, MAX_LEN_OF_HT_RATES);
+
+ pEntry->SupportRateMode = 0;
+
+ for(idx = 0; idx < SupportedRatesLen; idx ++)
+ {
+ switch((SupportedRates[idx] & 0x7F)*5)
+ {
+ case 10:
+ pEntry->SupportCCKMCS[MCS_0] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_CCK_MODE;
+ break;
+
+ case 20:
+ pEntry->SupportCCKMCS[MCS_1] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_CCK_MODE;
+ break;
+
+ case 55:
+ pEntry->SupportCCKMCS[MCS_2] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_CCK_MODE;
+ break;
+
+ case 110:
+ pEntry->SupportCCKMCS[MCS_3] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_CCK_MODE;
+ break;
+
+ case 60:
+ pEntry->SupportOFDMMCS[MCS_0] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 90:
+ pEntry->SupportOFDMMCS[MCS_1] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 120:
+ pEntry->SupportOFDMMCS[MCS_2] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 180:
+ pEntry->SupportOFDMMCS[MCS_3] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 240:
+ pEntry->SupportOFDMMCS[MCS_4] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 360:
+ pEntry->SupportOFDMMCS[MCS_5] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 480:
+ pEntry->SupportOFDMMCS[MCS_6] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+
+ case 540:
+ pEntry->SupportOFDMMCS[MCS_7] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_OFDM_MODE;
+ break;
+ }
+ }
+
+ if (HtCapabilityLen)
+ {
+ PRT_HT_PHY_INFO pDesired_ht_phy = NULL;
+ UCHAR j, bitmask;
+ CHAR i;
+
+
+#ifdef CONFIG_AP_SUPPORT
+ if (OpMode == OPMODE_AP)
+ {
+#ifdef WDS_SUPPORT
+ if (IS_ENTRY_WDS(pEntry))
+ pDesired_ht_phy = &pAd->WdsTab.WdsEntry[pEntry->apidx].DesiredHtPhyInfo;
+ else
+#endif /* WDS_SUPPORT */
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ pDesired_ht_phy = &pAd->ApCfg.ApCliTab[pEntry->apidx].DesiredHtPhyInfo;
+ else
+#endif /* APCLI_SUPPORT */
+ pDesired_ht_phy = &pAd->ApCfg.MBSSID[pEntry->apidx].DesiredHtPhyInfo;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ if (pDesired_ht_phy == NULL)
+ return;
+
+ for (i = 23; i >= 0; i--)
+ {
+ j = i / 8;
+ bitmask = (1 << (i - (j * 8)));
+
+ if ((pDesired_ht_phy->MCSSet[j] & bitmask)
+ && (pHtCapability->MCSSet[j] & bitmask))
+ {
+ pEntry->SupportHTMCS[i] = TRUE;
+ pEntry->SupportRateMode |= SUPPORT_HT_MODE;
+ }
+ }
+ }
+}
+
+INT Set_RateAlg_Proc(
+ IN PRTMP_ADAPTER pAd,
+ IN PSTRING arg)
+{
+ UINT32 ra_alg;
+
+ ra_alg = simple_strtol(arg, 0, 10);
+
+ if ((ra_alg < RATE_ALG_MAX_NUM) && (ra_alg != pAd->rateAlg))
+ {
+ UINT32 IdEntry;
+
+ pAd->rateAlg = ra_alg;
+ for(IdEntry = 0; IdEntry < MAX_LEN_OF_MAC_TABLE; IdEntry++)
+ pAd->MacTab.Content[IdEntry].rateAlg = ra_alg;
+ }
+
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: Set Alg = %d\n", __FUNCTION__, ra_alg));
+ return TRUE;
+}
+
+