extractedLnx/linux-2.6.30/drivers/staging/rt3070/common/mlme.c_MlmeDynamicTxRateSwitching.c
VOID MlmeDynamicTxRateSwitching(
IN PRTMP_ADAPTER pAd)
{
UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
ULONG i, AccuTxTotalCnt = 0, TxTotalCnt;
ULONG TxErrorRatio = 0;
BOOLEAN bTxRateChanged, bUpgradeQuality = FALSE;
PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL;
PUCHAR pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx = 0, TrainUp, TrainDown;
CHAR Rssi, RssiOffset = 0;
TX_STA_CNT1_STRUC StaTx1;
TX_STA_CNT0_STRUC TxStaCnt0;
ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
MAC_TABLE_ENTRY *pEntry;
#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++)
{
pEntry = &pAd->MacTab.Content[i];
// check if this entry need to switch rate automatically
if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
continue;
if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls))
{
Rssi = RTMPMaxRssi(pAd,
pAd->StaCfg.RssiSample.AvgRssi0,
pAd->StaCfg.RssiSample.AvgRssi1,
pAd->StaCfg.RssiSample.AvgRssi2);
// Update statistic counter
RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
pAd->bUpdateBcnCntDone = TRUE;
TxRetransmit = StaTx1.field.TxRetransmit;
TxSuccess = StaTx1.field.TxSuccess;
TxFailCount = TxStaCnt0.field.TxFailCount;
TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit;
pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess;
pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount;
pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess;
pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit;
pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount;
// if no traffic in the past 1-sec period, don't change TX rate,
// but clear all bad history. because the bad history may affect the next
// Chariot throughput test
AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
pAd->RalinkCounters.OneSecTxRetryOkCount +
pAd->RalinkCounters.OneSecTxFailCount;
if (TxTotalCnt)
TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
}
else
{
if (INFRA_ON(pAd) && (i == 1))
Rssi = RTMPMaxRssi(pAd,
pAd->StaCfg.RssiSample.AvgRssi0,
pAd->StaCfg.RssiSample.AvgRssi1,
pAd->StaCfg.RssiSample.AvgRssi2);
else
Rssi = RTMPMaxRssi(pAd,
pEntry->RssiSample.AvgRssi0,
pEntry->RssiSample.AvgRssi1,
pEntry->RssiSample.AvgRssi2);
TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
pEntry->OneSecTxRetryOkCount +
pEntry->OneSecTxFailCount;
if (TxTotalCnt)
TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt;
}
CurrRateIdx = pEntry->CurrTxRateIndex;
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
if (CurrRateIdx >= TableSize)
{
CurrRateIdx = TableSize - 1;
}
// When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex.
// So need to sync here.
pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];
if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS)
//&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE)
)
{
// Need to sync Real Tx rate and our record.
// Then return for next DRS.
pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5];
pEntry->CurrTxRateIndex = InitTxRateIdx;
MlmeSetTxRate(pAd, pEntry, pCurrTxRate);
// reset all OneSecTx counters
RESET_ONE_SEC_TX_CNT(pEntry);
continue;
}
// decide the next upgrade rate and downgrade rate, if any
if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1)))
{
UpRateIdx = CurrRateIdx + 1;
DownRateIdx = CurrRateIdx -1;
}
else if (CurrRateIdx == 0)
{
UpRateIdx = CurrRateIdx + 1;
DownRateIdx = CurrRateIdx;
}
else if (CurrRateIdx == (TableSize - 1))
{
UpRateIdx = CurrRateIdx;
DownRateIdx = CurrRateIdx - 1;
}
pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];
#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;
}
//pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction;
//
// Keep the last time TxRateChangeAction status.
//
pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction;
//
// CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI
// (criteria copied from RT2500 for Netopia case)
//
if (TxTotalCnt <= 15)
{
CHAR idx = 0;
UCHAR TxRateIdx;
//UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0;
UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3
// check the existence and index of each needed MCS
while (idx < pTable[0])
{
pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5];
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)
else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput
{
MCS7 = 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) && (pCurrTxRate->ShortGI == GI_800))
{
MCS15 = idx;
}
else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3
{
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 ++;
}
if (pAd->LatchRfRegs.Channel <= 14)
{
if (pAd->NicConfig2.field.ExternalLNAForG)
{
RssiOffset = 2;
}
else
{
RssiOffset = 5;
}
}
else
{
if (pAd->NicConfig2.field.ExternalLNAForA)
{
RssiOffset = 5;
}
else
{
RssiOffset = 8;
}
}
#ifdef DOT11_N_SUPPORT
/*if (MCS15)*/
if ((pTable == RateSwitchTable11BGN3S) ||
(pTable == RateSwitchTable11N3S) ||
(pTable == RateSwitchTable))
{// N mode with 3 stream // 3*3
if (MCS23 && (Rssi >= -70))
TxRateIdx = MCS15;
else if (MCS22 && (Rssi >= -72))
TxRateIdx = MCS14;
else if (MCS21 && (Rssi >= -76))
TxRateIdx = MCS13;
else if (MCS20 && (Rssi >= -78))
TxRateIdx = MCS12;
else if (MCS4 && (Rssi >= -82))
TxRateIdx = MCS4;
else if (MCS3 && (Rssi >= -84))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi >= -86))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi >= -88))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
}
// else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable))
else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3
{// N mode with 2 stream
if (MCS15 && (Rssi >= (-70+RssiOffset)))
TxRateIdx = MCS15;
else if (MCS14 && (Rssi >= (-72+RssiOffset)))
TxRateIdx = MCS14;
else if (MCS13 && (Rssi >= (-76+RssiOffset)))
TxRateIdx = MCS13;
else if (MCS12 && (Rssi >= (-78+RssiOffset)))
TxRateIdx = MCS12;
else if (MCS4 && (Rssi >= (-82+RssiOffset)))
TxRateIdx = MCS4;
else if (MCS3 && (Rssi >= (-84+RssiOffset)))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi >= (-86+RssiOffset)))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi >= (-88+RssiOffset)))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
}
else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S))
{// N mode with 1 stream
if (MCS7 && (Rssi > (-72+RssiOffset)))
TxRateIdx = MCS7;
else if (MCS6 && (Rssi > (-74+RssiOffset)))
TxRateIdx = MCS6;
else if (MCS5 && (Rssi > (-77+RssiOffset)))
TxRateIdx = MCS5;
else if (MCS4 && (Rssi > (-79+RssiOffset)))
TxRateIdx = MCS4;
else if (MCS3 && (Rssi > (-81+RssiOffset)))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi > (-83+RssiOffset)))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi > (-86+RssiOffset)))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
}
else
#endif // DOT11_N_SUPPORT //
{// Legacy mode
if (MCS7 && (Rssi > -70))
TxRateIdx = MCS7;
else if (MCS6 && (Rssi > -74))
TxRateIdx = MCS6;
else if (MCS5 && (Rssi > -78))
TxRateIdx = MCS5;
else if (MCS4 && (Rssi > -82))
TxRateIdx = MCS4;
else if (MCS4 == 0) // for B-only mode
TxRateIdx = MCS3;
else if (MCS3 && (Rssi > -85))
TxRateIdx = MCS3;
else if (MCS2 && (Rssi > -87))
TxRateIdx = MCS2;
else if (MCS1 && (Rssi > -90))
TxRateIdx = MCS1;
else
TxRateIdx = MCS0;
}
// if (TxRateIdx != pAd->CommonCfg.TxRateIndex)
{
pEntry->CurrTxRateIndex = TxRateIdx;
pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5];
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);
pEntry->fLastSecAccordingRSSI = TRUE;
// reset all OneSecTx counters
RESET_ONE_SEC_TX_CNT(pEntry);
continue;
}
if (pEntry->fLastSecAccordingRSSI == TRUE)
{
pEntry->fLastSecAccordingRSSI = FALSE;
pEntry->LastSecTxRateChangeAction = 0;
// reset all OneSecTx counters
RESET_ONE_SEC_TX_CNT(pEntry);
continue;
}
do
{
BOOLEAN bTrainUpDown = FALSE;
pEntry->CurrTxRateStableTime ++;
// downgrade TX quality if PER >= Rate-Down threshold
if (TxErrorRatio >= TrainDown)
{
bTrainUpDown = TRUE;
pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
}
// upgrade TX quality if PER <= Rate-Up threshold
else if (TxErrorRatio <= TrainUp)
{
bTrainUpDown = TRUE;
bUpgradeQuality = TRUE;
if (pEntry->TxQuality[CurrRateIdx])
pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate
if (pEntry->TxRateUpPenalty)
pEntry->TxRateUpPenalty --;
else if (pEntry->TxQuality[UpRateIdx])
pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality
}
pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio;
if (bTrainUpDown)
{
// perform DRS - consider TxRate Down first, then rate up.
if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND))
{
pEntry->CurrTxRateIndex = DownRateIdx;
}
else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0))
{
pEntry->CurrTxRateIndex = UpRateIdx;
}
}
} while (FALSE);
// if rate-up happen, clear all bad history of all TX rates
if (pEntry->CurrTxRateIndex > CurrRateIdx)
{
pEntry->CurrTxRateStableTime = 0;
pEntry->TxRateUpPenalty = 0;
pEntry->LastSecTxRateChangeAction = 1; // rate UP
NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);
//
// For TxRate fast train up
//
if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning)
{
RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100);
pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE;
}
bTxRateChanged = TRUE;
}
// if rate-down happen, only clear DownRate's bad history
else if (pEntry->CurrTxRateIndex < CurrRateIdx)
{
pEntry->CurrTxRateStableTime = 0;
pEntry->TxRateUpPenalty = 0; // no penalty
pEntry->LastSecTxRateChangeAction = 2; // rate DOWN
pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
pEntry->PER[pEntry->CurrTxRateIndex] = 0;
//
// For TxRate fast train down
//
if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning)
{
RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100);
pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE;
}
bTxRateChanged = TRUE;
}
else
{
pEntry->LastSecTxRateChangeAction = 0; // rate no change
bTxRateChanged = FALSE;
}
pEntry->LastTxOkCount = TxSuccess;
// reset all OneSecTx counters
RESET_ONE_SEC_TX_CNT(pEntry);
pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5];
if (bTxRateChanged && pNextTxRate)
{
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
}
}
Generated by GNU enscript 1.6.4.