summaryrefslogtreecommitdiff
path: root/cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c
diff options
context:
space:
mode:
authorFisher Cheng2012-11-30 17:41:08 +0800
committerJulien Lacour2013-10-01 11:30:32 +0200
commit1acf0f895c26837099eeaff6455152dd94fa6d53 (patch)
treef841b2c132fff301ef00d74f1e3dd8ae21341db0 /cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c
parentca15306cb8a92c9f2abfc816ef5b69545c838d9f (diff)
cleo/devkit: add Ralink RT5572 driver source code, refs #4213
Diffstat (limited to 'cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c')
-rw-r--r--cleopatre/devkit/rt5572drv/MODULE/rate_ctrl/alg_legacy.c899
1 files changed, 899 insertions, 0 deletions
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);
+ }
+}