extractedLnx/linux-2.6.38/drivers/staging/rt2860/common/mlme.c_MlmeDynamicTxRateSwitching.c
void MlmeDynamicTxRateSwitching(struct rt_rtmp_adapter *pAd)
{
u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
unsigned long i, AccuTxTotalCnt = 0, TxTotalCnt;
unsigned long TxErrorRatio = 0;
BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE;
struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
u8 *pTable;
u8 TableSize = 0;
u8 InitTxRateIdx = 0, TrainUp, TrainDown;
char Rssi, RssiOffset = 0;
TX_STA_CNT1_STRUC StaTx1;
TX_STA_CNT0_STRUC TxStaCnt0;
unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
struct rt_mac_table_entry *pEntry;
struct rt_rssi_sample *pRssi = &pAd->StaCfg.RssiSample;
/* */
/* 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,
pRssi->AvgRssi0,
pRssi->AvgRssi1, pRssi->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,
pRssi->AvgRssi0,
pRssi->AvgRssi1,
pRssi->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;
}
if (TxTotalCnt) {
/*
Three AdHoc connections can not work normally if one AdHoc connection is disappeared from a heavy traffic environment generated by ping tool
We force to set LongRtyLimit and ShortRtyLimit to 0 to stop retransmitting packet, after a while, resoring original settings
*/
if (TxErrorRatio == 100) {
TX_RTY_CFG_STRUC TxRtyCfg, TxRtyCfgtmp;
unsigned long Index;
unsigned long MACValue;
RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
TxRtyCfgtmp.word = TxRtyCfg.word;
TxRtyCfg.field.LongRtyLimit = 0x0;
TxRtyCfg.field.ShortRtyLimit = 0x0;
RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
RTMPusecDelay(1);
Index = 0;
MACValue = 0;
do {
RTMP_IO_READ32(pAd, TXRXQ_PCNT,
&MACValue);
if ((MACValue & 0xffffff) == 0)
break;
Index++;
RTMPusecDelay(1000);
} while ((Index < 330)
&&
(!RTMP_TEST_FLAG
(pAd,
fRTMP_ADAPTER_HALT_IN_PROGRESS)));
RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
TxRtyCfg.field.LongRtyLimit =
TxRtyCfgtmp.field.LongRtyLimit;
TxRtyCfg.field.ShortRtyLimit =
TxRtyCfgtmp.field.ShortRtyLimit;
RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
}
}
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 =
(struct rt_rtmp_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 =
(struct rt_rtmp_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 =
(struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
if ((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;
}
/*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;
u8 TxRateIdx;
u8 MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 =
0, MCS5 = 0, MCS6 = 0, MCS7 = 0;
u8 MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
u8 MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; /* 3*3 */
/* check the existence and index of each needed MCS */
while (idx < pTable[0]) {
pCurrTxRate =
(struct rt_rtmp_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)) /*we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI */
{
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;
}
}
/*if (MCS15) */
if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || (pTable == RateSwitchTable)) { /* N mode with 3 stream // 3*3 */
if (MCS23 && (Rssi >= -70))
TxRateIdx = MCS23;
else if (MCS22 && (Rssi >= -72))
TxRateIdx = MCS22;
else if (MCS21 && (Rssi >= -76))
TxRateIdx = MCS21;
else if (MCS20 && (Rssi >= -78))
TxRateIdx = MCS20;
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 { /* 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 =
(struct rt_rtmp_tx_rate_switch *) &
pTable[(pEntry->CurrTxRateIndex + 1) * 5];
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
NdisZeroMemory(pEntry->TxQuality,
sizeof(u16)*
MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER,
sizeof(u8)*
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] = (u8)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(u16)*
MAX_STEP_OF_TX_RATE_SWITCH);
NdisZeroMemory(pEntry->PER,
sizeof(u8)*
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;
{
u8 tmpTxRate;
/* to fix tcp ack issue */
if (!bTxRateChanged
&& (pAd->RalinkCounters.OneSecReceivedByteCount >
(pAd->RalinkCounters.
OneSecTransmittedByteCount * 5))) {
tmpTxRate = DownRateIdx;
DBGPRINT_RAW(RT_DEBUG_TRACE,
("DRS: Rx(%d) is 5 times larger than Tx(%d), use low rate (curr=%d, tmp=%d)\n",
pAd->RalinkCounters.
OneSecReceivedByteCount,
pAd->RalinkCounters.
OneSecTransmittedByteCount,
pEntry->CurrTxRateIndex,
tmpTxRate));
} else {
tmpTxRate = pEntry->CurrTxRateIndex;
}
pNextTxRate =
(struct rt_rtmp_tx_rate_switch *) & pTable[(tmpTxRate + 1) *
5];
}
if (bTxRateChanged && pNextTxRate) {
MlmeSetTxRate(pAd, pEntry, pNextTxRate);
}
/* reset all OneSecTx counters */
RESET_ONE_SEC_TX_CNT(pEntry);
}
}
Generated by GNU enscript 1.6.4.