Enscript Output

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.