📄 mlme.c
字号:
NOTE:
call this routine every second
==========================================================================
*/
VOID MlmeDynamicTxRateSwitching(
IN PRTMP_ADAPTER pAd)
{
UCHAR UpRate, DownRate, CurrRate;
ULONG TxTotalCnt, NewBasicRateBitmap;
ULONG TxErrorRatio = 0;
BOOLEAN fUpgradeQuality = FALSE;
SHORT dbm = pAd->PortCfg.AvgRssi - pAd->BbpRssiToDbmDelta;
CurrRate = pAd->PortCfg.TxRate;
// do not reply ACK using TX rate higher than normal DATA TX rate
NewBasicRateBitmap = pAd->PortCfg.BasicRateBitmap & BasicRateMask[CurrRate];
RTUSBWriteMACRegister(pAd, TXRX_CSR5, NewBasicRateBitmap);
// 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
TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
pAd->RalinkCounters.OneSecTxRetryOkCount +
pAd->RalinkCounters.OneSecTxFailCount;
if (TxTotalCnt)
TxErrorRatio = ((pAd->RalinkCounters.OneSecTxRetryOkCount + pAd->RalinkCounters.OneSecTxFailCount) *100) / TxTotalCnt;
DBGPRINT_RAW(RT_DEBUG_TRACE,"%d: NDIS push BE=%d, BK=%d, VI=%d, VO=%d, TX/RX AGGR=<%d,%d>, p-NDIS=%d, RSSI=%d, ACKbmap=%03x, PER=%d%%\n",
RateIdToMbps[CurrRate],
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE],
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK],
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI],
pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO],
pAd->RalinkCounters.OneSecTxAggregationCount,
pAd->RalinkCounters.OneSecRxAggregationCount,
pAd->RalinkCounters.PendingNdisPacketCount,
dbm,
NewBasicRateBitmap & 0xfff,
TxErrorRatio);
if (! OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))
return;
//
// 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)
{
TxErrorRatio = 0;
pAd->DrsCounters.TxRateUpPenalty = 0;
NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
if (dbm >= -65)
pAd->PortCfg.TxRate = RATE_54;
else if (dbm >= -66)
pAd->PortCfg.TxRate = RATE_48;
else if (dbm >= -70)
pAd->PortCfg.TxRate = RATE_36;
else if (dbm >= -74)
pAd->PortCfg.TxRate = RATE_24;
else if (dbm >= -77)
pAd->PortCfg.TxRate = RATE_18;
else if (dbm >= -79)
pAd->PortCfg.TxRate = RATE_12;
else if (dbm >= -81)
{
// in 11A or 11G-only mode, no CCK rates available
if ((pAd->PortCfg.Channel > 14) || (pAd->PortCfg.PhyMode == PHY_11G))
pAd->PortCfg.TxRate = RATE_9;
else
pAd->PortCfg.TxRate = RATE_11;
}
else
{
// in 11A or 11G-only mode, no CCK rates available
if ((pAd->PortCfg.Channel > 14) || (pAd->PortCfg.PhyMode == PHY_11G))
pAd->PortCfg.TxRate = RATE_6;
else
{
if (dbm >= -82)
pAd->PortCfg.TxRate = RATE_11;
else if (dbm >= -84)
pAd->PortCfg.TxRate = RATE_5_5;
else if (dbm >= -85)
pAd->PortCfg.TxRate = RATE_2;
else
pAd->PortCfg.TxRate = RATE_1;
}
}
if (pAd->PortCfg.TxRate > pAd->PortCfg.MaxTxRate)
pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
return;
}
//
// CASE2. enough TX samples, tune TX rate based on TxPER
//
do
{
pAd->DrsCounters.CurrTxRateStableTime ++;
// decide the next upgrade rate and downgrade rate, if any
if ((pAd->PortCfg.Channel > 14) || // must be in 802.11A band
(pAd->PortCfg.PhyMode == PHY_11G)) // G-only mode, no CCK rates available
{
UpRate = Phy11ANextRateUpward[CurrRate];
DownRate = Phy11ANextRateDownward[CurrRate];
}
else
{
UpRate = Phy11BGNextRateUpward[CurrRate];
DownRate = Phy11BGNextRateDownward[CurrRate];
}
if (UpRate > pAd->PortCfg.MaxTxRate)
UpRate = pAd->PortCfg.MaxTxRate;
TxErrorRatio = ((pAd->RalinkCounters.OneSecTxRetryOkCount + pAd->RalinkCounters.OneSecTxFailCount) *100) / TxTotalCnt;
// downgrade TX quality if PER >= Rate-Down threshold
if (TxErrorRatio >= RateDownPER[CurrRate])
{
pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
}
// upgrade TX quality if PER <= Rate-Up threshold
else if (TxErrorRatio <= RateUpPER[CurrRate])
{
fUpgradeQuality = TRUE;
if (pAd->DrsCounters.TxQuality[CurrRate])
pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate
if (pAd->DrsCounters.TxRateUpPenalty)
pAd->DrsCounters.TxRateUpPenalty --;
else if (pAd->DrsCounters.TxQuality[UpRate])
pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality
}
pAd->DrsCounters.PER[CurrRate] = (UCHAR)TxErrorRatio;
#if 1
// 2004-3-13 special case: Claim noisy environment
// decide if there was a false "rate down" in the past 2 sec due to noisy
// environment. if so, we would rather switch back to the higher TX rate.
// criteria -
// 1. there's a higher rate available, AND
// 2. there was a rate-down happened, AND
// 3. current rate has 75% > PER > 20%, AND
// 4. comparing to UpRate, current rate didn't improve PER more than 5 %
if ((UpRate != CurrRate) &&
(pAd->DrsCounters.LastSecTxRateChangeAction == 2) &&
(pAd->DrsCounters.PER[CurrRate] < 75) &&
((pAd->DrsCounters.PER[CurrRate] > 20) || (pAd->DrsCounters.fNoisyEnvironment)) &&
((pAd->DrsCounters.PER[CurrRate]+5) > pAd->DrsCounters.PER[UpRate]))
{
// we believe this is a noisy environment. better stay at UpRate
DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: #### enter Noisy environment ####\n");
pAd->DrsCounters.fNoisyEnvironment = TRUE;
// 2004-3-14 when claiming noisy environment, we're not only switch back
// to UpRate, but can be more aggressive to use one more rate up
UpRate++;
if ((UpRate==RATE_6) || (UpRate==RATE_9)) UpRate=RATE_12;
if (UpRate > pAd->PortCfg.MaxTxRate)
UpRate = pAd->PortCfg.MaxTxRate;
pAd->PortCfg.TxRate = UpRate;
break;
}
// 2004-3-12 special case: Leave noisy environment
// The interference has gone suddenly. reset TX rate to
// the theoritical value according to RSSI. Criteria -
// 1. it's currently in noisy environment
// 2. PER drops to be below 12%
if ((pAd->DrsCounters.fNoisyEnvironment == TRUE) &&
(pAd->DrsCounters.PER[CurrRate] <= 12))
{
UCHAR JumpUpRate;
pAd->DrsCounters.fNoisyEnvironment = FALSE;
for (JumpUpRate = RATE_54; JumpUpRate > RATE_1; JumpUpRate--)
{
if (dbm > RssiSafeLevelForTxRate[JumpUpRate])
break;
}
if (JumpUpRate > pAd->PortCfg.MaxTxRate)
JumpUpRate = pAd->PortCfg.MaxTxRate;
DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: #### leave Noisy environment ####, RSSI=%d, JumpUpRate=%d\n",
dbm, RateIdToMbps[JumpUpRate]);
if (JumpUpRate > CurrRate)
{
pAd->PortCfg.TxRate = JumpUpRate;
break;
}
}
#endif
// we're going to upgrade CurrRate to UpRate at next few seconds,
// but before that, we'd better try a NULL frame @ UpRate and
// see if UpRate is stable or not. If this NULL frame fails, it will
// downgrade TxQuality[CurrRate], so that STA won't switch to
// to UpRate in the next second
// 2004-04-07 requested by David Tung - sent test frames only in OFDM rates
if (fUpgradeQuality &&
INFRA_ON(pAd) &&
(UpRate != CurrRate) &&
(UpRate > RATE_11) &&
(pAd->DrsCounters.TxQuality[CurrRate] <= 1) &&
(pAd->DrsCounters.TxQuality[UpRate] <= 1))
{
DBGPRINT_RAW(RT_DEBUG_TRACE,"DRS: 2 NULL frames at UpRate = %d Mbps\n",RateIdToMbps[UpRate]);
RTMPSendNullFrame(pAd, UpRate);
}
// perform DRS - consider TxRate Down first, then rate up.
// 1. rate down, if current TX rate's quality is not good
// 2. rate up, if UPRate's quality is very good
if ((pAd->DrsCounters.TxQuality[CurrRate] >= DRS_TX_QUALITY_WORST_BOUND) &&
(CurrRate != DownRate))
{
#if 1
// guarantee a minimum TX rate for each RSSI segments
if ((dbm >= -45) && (DownRate < RATE_48))
pAd->PortCfg.TxRate = RATE_48;
else if ((dbm >= -50) && (DownRate < RATE_36))
pAd->PortCfg.TxRate = RATE_36;
else if ((dbm >= -55) && (DownRate < RATE_24))
pAd->PortCfg.TxRate = RATE_24;
else if ((dbm >= -60) && (DownRate < RATE_18))
pAd->PortCfg.TxRate = RATE_18;
else if ((dbm >= -65) && (DownRate < RATE_12))
pAd->PortCfg.TxRate = RATE_12;
else if ((dbm >= -70) && (DownRate < RATE_9))
{
// in 11A or 11G-only mode, no CCK rates available
if ((pAd->PortCfg.Channel > 14) || (pAd->PortCfg.PhyMode == PHY_11G))
pAd->PortCfg.TxRate = RATE_9;
else
pAd->PortCfg.TxRate = RATE_11;
}
else
#endif
{
if ((dbm >= -75) && (DownRate < RATE_11))
pAd->PortCfg.TxRate = RATE_11;
else
{
#ifdef WIFI_TEST
if (DownRate <= RATE_2) break; // never goes lower than 5.5 Mbps TX rate
#endif
// otherwise, if DownRate still better than the low bound that current RSSI can support,
// go straight to DownRate
pAd->PortCfg.TxRate = DownRate;
}
}
}
else if ((pAd->DrsCounters.TxQuality[CurrRate] <= 0) &&
(pAd->DrsCounters.TxQuality[UpRate] <=0) &&
(CurrRate != UpRate))
{
pAd->PortCfg.TxRate = UpRate;
}
//
// To make sure TxRate didn't over MaxTxRate
//
if (pAd->PortCfg.TxRate > pAd->PortCfg.MaxTxRate)
pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
}while (FALSE);
// if rate-up happen, clear all bad history of all TX rates
if (pAd->PortCfg.TxRate > CurrRate)
{
DBGPRINT(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
pAd->DrsCounters.CurrTxRateStableTime = 0;
pAd->DrsCounters.TxRateUpPenalty = 0;
pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP
NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
#if 0
//This mechanism should be changed on USB device.
//
// For TxRate fast train up, issued by David 2005/05/12
//
if (!pAd->PortCfg.QuickResponeForRateUpTimerRunning)
{
if (pAd->PortCfg.TxRate <= RATE_12)
RTMPSetTimer(pAd, &pAd->PortCfg.QuickResponeForRateUpTimer, 200);
else
RTMPSetTimer(pAd, &pAd->PortCfg.QuickResponeForRateUpTimer, 100);
pAd->PortCfg.QuickResponeForRateUpTimerRunning = TRUE;
}
#endif
}
// if rate-down happen, only clear DownRate's bad history
else if (pAd->PortCfg.TxRate < CurrRate)
{
DBGPRINT(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
#if 0
//Remove this code for TxRate fast train up. issued by David 2005/05/12
// shorter stable time require more penalty in next rate UP criteria
//if (pAd->DrsCounters.CurrTxRateStableTime < 4) // less then 4 sec
// pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty
//else if (pAd->DrsCounters.CurrTxRateStableTime < 8) // less then 8 sec
// pAd->DrsCounters.TxRateUpPenalty = 2; // add 2 sec penalty
//else // >= 8 sec
#endif
pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty
pAd->DrsCounters.CurrTxRateStableTime = 0;
pAd->DrsCounters.LastSecTxRateChangeAction = 2; // rate DOWN
pAd->DrsCounters.TxQuality[pAd->PortCfg.TxRate] = 0;
pAd->DrsCounters.PER[pAd->PortCfg.TxRate] = 0;
}
else
pAd->DrsCounters.LastSecTxRateChangeAction = 0; // rate no change
}
/*
==========================================================================
Description:
This routine is executed periodically inside MlmePeriodicExec() after
association with an AP.
It checks if PortCfg.Psm is consistent with user policy (recorded in
PortCfg.WindowsPowerMode). If not, enforce user policy. However,
there're some conditions to consider:
1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
the time when Mibss==TRUE
2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE
if outgoing traffic available in TxRing or MgmtRing.
Output:
1. change pAd->PortCfg.Psm to PWR_SAVE or leave it untouched
==========================================================================
*/
VOID MlmeCheckPsmChange(
IN PRTMP_ADAPTER pAd,
IN ULONG Now32)
{
ULONG PowerMode;
// condition -
// 1. Psm maybe ON only happen in INFRASTRUCTURE mode
// 2. user wants either MAX_PSP or FAST_PSP
// 3. but curr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -