/*++
Copyright (c) Realtek Semiconductor Corp. All rights reserved.

Module Name:
	RateAdaptive.c

Abstract:
	Implement Rate Adaptive functions for common operations.

Major Change History:
	When       Who               What
	---------- ---------------   -------------------------------
	2011-08-12 Page            Create.

--*/
#include "odm_precomp.h"

/* if ( DM_ODM_SUPPORT_TYPE == ODM_MP) */
/* include "Mp_Precomp.h" */
/* endif */

#if (RATE_ADAPTIVE_SUPPORT == 1)
/*  Rate adaptive parameters */


static u1Byte RETRY_PENALTY[PERENTRY][RETRYSIZE+1] = {
		{5,4,3,2,0,3},/* 92 , idx=0 */
		{6,5,4,3,0,4},/* 86 , idx=1 */
		{6,5,4,2,0,4},/* 81 , idx=2 */
		{8,7,6,4,0,6},/* 75 , idx=3 */
		{10,9,8,6,0,8},/* 71	, idx=4 */
		{10,9,8,4,0,8},/* 66	, idx=5 */
		{10,9,8,2,0,8},/* 62	, idx=6 */
		{10,9,8,0,0,8},/* 59	, idx=7 */
		{18,17,16,8,0,16},/* 53 , idx=8 */
		{26,25,24,16,0,24},/* 50	, idx=9 */
		{34,33,32,24,0,32},/* 47	, idx=0x0a */
		{34,31,28,20,0,32},/* 43	, idx=0x0b */
		{34,31,27,18,0,32},/* 40 , idx=0x0c */
		{34,31,26,16,0,32},/* 37 , idx=0x0d */
		{34,30,22,16,0,32},/* 32 , idx=0x0e */
		{34,30,24,16,0,32},/* 26 , idx=0x0f */
		{49,46,40,16,0,48},/* 20	, idx=0x10 */
		{49,45,32,0,0,48},/* 17 , idx=0x11 */
		{49,45,22,18,0,48},/* 15	, idx=0x12 */
		{49,40,24,16,0,48},/* 12	, idx=0x13 */
		{49,32,18,12,0,48},/* 9 , idx=0x14 */
		{49,22,18,14,0,48},/* 6 , idx=0x15 */
		{49,16,16,0,0,48}};/* 3, idx=0x16 */

static u1Byte	RETRY_PENALTY_UP[RETRYSIZE+1]={49,44,16,16,0,48};  /*  12% for rate up */

static u1Byte PT_PENALTY[RETRYSIZE+1]={34,31,30,24,0,32};

#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
static u1Byte	RETRY_PENALTY_IDX[2][RATESIZE] =	{
		{4,4,4,5,4,4,5,7,7,7,8,0x0a,	       /*  SS>TH */
		4,4,4,4,6,0x0a,0x0b,0x0d,
		5,5,7,7,8,0x0b,0x0d,0x0f},			   /*  0329 R01 */
		{0x0a,0x0a,0x0a,0x0a,0x0c,0x0c,0x0e,0x10,0x11,0x12,0x12,0x13,	   /*  SS<TH */
		0x0e,0x0f,0x10,0x10,0x11,0x14,0x14,0x15,
		9,9,9,9,0x0c,0x0e,0x11,0x13}};

static u1Byte	RETRY_PENALTY_UP_IDX[RATESIZE] = {
		0x10,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,	       /*  SS>TH */
		0x13,0x13,0x14,0x14,0x15,0x15,0x15,0x15,
		0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15};

static u1Byte	RSSI_THRESHOLD[RATESIZE] = {
		0,0,0,0,
		0,0,0,0,0,0x24,0x26,0x2a,
		0x13,0x15,0x17,0x18,0x1a,0x1c,0x1d,0x1f,
		0,0,0,0x1f,0x23,0x28,0x2a,0x2c};
#else

/*  wilson modify */
static u1Byte	RETRY_PENALTY_IDX[2][RATESIZE] = {
		{4,4,4,5,4,4,5,7,7,7,8,0x0a,	       /*  SS>TH */
		4,4,4,4,6,0x0a,0x0b,0x0d,
		5,5,7,7,8,0x0b,0x0d,0x0f},			   /*  0329 R01 */
		{0x0a,0x0a,0x0b,0x0c,0x0a,
		0x0a,0x0b,0x0c,0x0d,0x10,0x13,0x14,	   /*  SS<TH */
		0x0b,0x0c,0x0d,0x0e,0x0f,0x11,0x13,0x15,
		9,9,9,9,0x0c,0x0e,0x11,0x13}};

static u1Byte	RETRY_PENALTY_UP_IDX[RATESIZE] = {
		0x0c,0x0d,0x0d,0x0f,0x0d,0x0e,
		0x0f,0x0f,0x10,0x12,0x13,0x14,	       /*  SS>TH */
		0x0f,0x10,0x10,0x12,0x12,0x13,0x14,0x15,
		0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15};

static u1Byte	RSSI_THRESHOLD[RATESIZE] = {
		0,0,0,0,
		0,0,0,0,0,0x24,0x26,0x2a,
		0x18,0x1a,0x1d,0x1f,0x21,0x27,0x29,0x2a,
		0,0,0,0x1f,0x23,0x28,0x2a,0x2c};

#endif

static u2Byte	N_THRESHOLD_HIGH[RATESIZE] = {
		4,4,8,16,
		24,36,48,72,96,144,192,216,
		60,80,100,160,240,400,560,640,
		300,320,480,720,1000,1200,1600,2000};
static u2Byte	N_THRESHOLD_LOW[RATESIZE] = {
		2,2,4,8,
		12,18,24,36,48,72,96,108,
		30,40,50,80,120,200,280,320,
		150,160,240,360,500,600,800,1000};
static u1Byte	 TRYING_NECESSARY[RATESIZE] = {
		2,2,2,2,
		2,2,3,3,4,4,5,7,
		4,4,7,10,10,12,12,18,
		5,7,7,8,11,18,36,60};  /*  0329  1207 */

static u1Byte	DROPING_NECESSARY[RATESIZE] = {
		1,1,1,1,
		1,2,3,4,5,6,7,8,
		1,2,3,4,5,6,7,8,
		5,6,7,8,9,10,11,12};

static u4Byte	INIT_RATE_FALLBACK_TABLE[16]={
		0x0f8ff015,  /*  0: 40M BGN mode */
		0x0f8ff010,   /*  1: 40M GN mode */
		0x0f8ff005,   /*  2: BN mode/ 40M BGN mode */
		0x0f8ff000,   /*  3: N mode */
		0x00000ff5,   /*  4: BG mode */
		0x00000ff0,   /*  5: G mode */
		0x0000000d,   /*  6: B mode */
		0,		/*  7: */
		0,		/*  8: */
		0,		/*  9: */
		0,		/*  10: */
		0,		/*  11: */
		0,		/*  12: */
		0,		/*  13: */
		0,		/*  14: */
		0,		/*  15: */
	};

static u1Byte PendingForRateUpFail[5] = {2,10,24,40,60};
static u2Byte DynamicTxRPTTiming[6] = {
	0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12 ,0x927c}; /*  200ms-1200ms */

/*  End Rate adaptive parameters */

static void odm_SetTxRPTTiming_8188E(
		PDM_ODM_T		pDM_Odm,
		PODM_RA_INFO_T		pRaInfo,
		u1Byte			extend
	)
{
	u1Byte idx = 0;

	for (idx=0; idx<5; idx++)
		if (DynamicTxRPTTiming[idx] == pRaInfo->RptTime)
			break;

	if (extend==0) /*  back to default timing */
		idx=0;  /* 200ms */
	else if (extend==1) {/*  increase the timing */
		idx+=1;
		if (idx>5)
			idx=5;
	}
	else if (extend==2) {/*  decrease the timing */
		if (idx!=0)
			idx-=1;
	}
	pRaInfo->RptTime=DynamicTxRPTTiming[idx];

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("pRaInfo->RptTime=0x%x\n", pRaInfo->RptTime));
}

static int odm_RateDown_8188E(
		PDM_ODM_T	pDM_Odm,
		PODM_RA_INFO_T  pRaInfo
	)
{
	u1Byte RateID, LowestRate, HighestRate;
	u1Byte i;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDown_8188E()\n"));
	if (NULL == pRaInfo)
	{
		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateDown_8188E(): pRaInfo is NULL\n"));
		return -1;
	}
	RateID = pRaInfo->PreRate;
	LowestRate = pRaInfo->LowestRate;
	HighestRate = pRaInfo->HighestRate;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
				(" RateID=%d LowestRate=%d HighestRate=%d RateSGI=%d\n",
				RateID, LowestRate, HighestRate, pRaInfo->RateSGI));
	if (RateID > HighestRate) {
		RateID=HighestRate;
	} else if (pRaInfo->RateSGI) {
		pRaInfo->RateSGI=0;
	} else if (RateID > LowestRate) {
		if (RateID > 0) {
			for (i=RateID-1; i>LowestRate;i--) {
				if (pRaInfo->RAUseRate & BIT(i)) {
					RateID=i;
					goto RateDownFinish;
				}
			}
		}
	} else if (RateID <= LowestRate) {
		RateID = LowestRate;
	}
RateDownFinish:
	if (pRaInfo->RAWaitingCounter==1){
		pRaInfo->RAWaitingCounter+=1;
		pRaInfo->RAPendingCounter+=1;
	} else if (pRaInfo->RAWaitingCounter==0){
	} else {
		pRaInfo->RAWaitingCounter=0;
		pRaInfo->RAPendingCounter=0;
	}

	if (pRaInfo->RAPendingCounter>=4)
		pRaInfo->RAPendingCounter=4;

	pRaInfo->DecisionRate=RateID;
	odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 2);
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down, RPT Timing default\n"));
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d",pRaInfo->RAWaitingCounter,pRaInfo->RAPendingCounter));
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI));
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateDown_8188E()\n"));
	return 0;
}

static int odm_RateUp_8188E(
		PDM_ODM_T		pDM_Odm,
		PODM_RA_INFO_T  pRaInfo
	)
{
	u1Byte RateID, HighestRate;
	u1Byte i;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateUp_8188E()\n"));
	if (NULL == pRaInfo) {
		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E(): pRaInfo is NULL\n"));
		return -1;
	}
	RateID = pRaInfo->PreRate;
	HighestRate = pRaInfo->HighestRate;
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
				(" RateID=%d HighestRate=%d\n",
				RateID, HighestRate));
	if (pRaInfo->RAWaitingCounter==1){
		pRaInfo->RAWaitingCounter=0;
		pRaInfo->RAPendingCounter=0;
	} else if (pRaInfo->RAWaitingCounter>1){
		pRaInfo->PreRssiStaRA=pRaInfo->RssiStaRA;
		goto RateUpfinish;
	}
	odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 0);
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E():Decrease RPT Timing\n"));

	if (RateID < HighestRate) {
		for (i=RateID+1; i<=HighestRate; i++) {
			if (pRaInfo->RAUseRate & BIT(i)) {
				RateID=i;
				goto RateUpfinish;
			}
		}
	} else if (RateID == HighestRate) {
		if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1))
			pRaInfo->RateSGI = 1;
		else if ((pRaInfo->SGIEnable) !=1 )
			pRaInfo->RateSGI = 0;
	} else {
		RateID = HighestRate;
	}
RateUpfinish:
	if (pRaInfo->RAWaitingCounter==(4+PendingForRateUpFail[pRaInfo->RAPendingCounter]))
		pRaInfo->RAWaitingCounter=0;
	else
		pRaInfo->RAWaitingCounter++;

	pRaInfo->DecisionRate=RateID;
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate up to RateID %d\n", RateID));
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d",pRaInfo->RAWaitingCounter,pRaInfo->RAPendingCounter));
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateUp_8188E()\n"));
	return 0;
}

static void odm_ResetRaCounter_8188E(PODM_RA_INFO_T  pRaInfo){
	u1Byte RateID;
	RateID=pRaInfo->DecisionRate;
	pRaInfo->NscUp=(N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1;
	pRaInfo->NscDown=(N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1;
}

static void odm_RateDecision_8188E(PDM_ODM_T		pDM_Odm,
		PODM_RA_INFO_T  pRaInfo
	)
{
	u1Byte RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0;
	/* u4Byte pool_retry; */
	static u1Byte DynamicTxRPTTimingCounter=0;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDecision_8188E()\n"));

	if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) /*  STA used and data packet exits */
	{
		if ( (pRaInfo->RssiStaRA<(pRaInfo->PreRssiStaRA-3))|| (pRaInfo->RssiStaRA>(pRaInfo->PreRssiStaRA+3))){
			pRaInfo->RAWaitingCounter=0;
			pRaInfo->RAPendingCounter=0;
		}
		/*  Start RA decision */
		if (pRaInfo->PreRate > pRaInfo->HighestRate)
			RateID = pRaInfo->HighestRate;
		else
			RateID = pRaInfo->PreRate;
		if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID])
			RtyPtID=0;
		else
			RtyPtID=1;
		PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; /* TODO by page */

		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
					(" NscDown init is %d\n", pRaInfo->NscDown));
		pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0];
		pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1];
		pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2];
		pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3];
		pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4];
		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
					(" NscDown is %d, total*penalty[5] is %d\n",
					pRaInfo->NscDown, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])));
		if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))
			pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5];
		else
			pRaInfo->NscDown=0;

		/*  rate up */
		PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID];
		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
					(" NscUp init is %d\n", pRaInfo->NscUp));
		pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0];
		pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1];
		pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2];
		pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3];
		pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4];
		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
					("NscUp is %d, total*up[5] is %d\n",
					pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])));
		if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))
			pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5];
		else
			pRaInfo->NscUp = 0;

		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE|ODM_COMP_INIT, ODM_DBG_LOUD,
					(" RssiStaRa= %d RtyPtID=%d PenaltyID1=0x%x  PenaltyID2=0x%x RateID=%d NscDown=%d NscUp=%d SGI=%d\n",
					pRaInfo->RssiStaRA,RtyPtID, PenaltyID1,PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI));
		if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) ||(pRaInfo->DROP>DROPING_NECESSARY[RateID]))
			odm_RateDown_8188E(pDM_Odm,pRaInfo);
		else if (pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID])
			odm_RateUp_8188E(pDM_Odm,pRaInfo);

		if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
			pRaInfo->DecisionRate = pRaInfo->HighestRate;

		if ((pRaInfo->DecisionRate)==(pRaInfo->PreRate))
			DynamicTxRPTTimingCounter+=1;
		else
			DynamicTxRPTTimingCounter=0;

		if (DynamicTxRPTTimingCounter>=4) {
			odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 1);
			ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<=====Rate don't change 4 times, Extend RPT Timing\n"));
			DynamicTxRPTTimingCounter=0;
		}

		pRaInfo->PreRate = pRaInfo->DecisionRate;  /* YJ,add,120120 */

		odm_ResetRaCounter_8188E(  pRaInfo);
	}
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateDecision_8188E()\n"));
}

static int
odm_ARFBRefresh_8188E(
		PDM_ODM_T		pDM_Odm,
		PODM_RA_INFO_T  pRaInfo
	)
{  /*  Wilson 2011/10/26 */
	u4Byte MaskFromReg;
	s1Byte i;

	switch (pRaInfo->RateID){
		case RATR_INX_WIRELESS_NGB:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff015;
			break;
		case RATR_INX_WIRELESS_NG:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff010;
			break;
		case RATR_INX_WIRELESS_NB:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff005;
			break;
		case RATR_INX_WIRELESS_N:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff000;
			break;
		case RATR_INX_WIRELESS_GB:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x00000ff5;
			break;
		case RATR_INX_WIRELESS_G:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x00000ff0;
			break;
		case RATR_INX_WIRELESS_B:
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0000000d;
			break;
		case 12:
			MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR0);
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg;
			break;
		case 13:
			MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR1);
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg;
			break;
		case 14:
			MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR2);
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg;
			break;
		case 15:
			MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR3);
			pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg;
			break;

		default:
			pRaInfo->RAUseRate=(pRaInfo->RateMask);
			break;
	}
	/*  Highest rate */
	if (pRaInfo->RAUseRate){
		for (i=RATESIZE;i>=0;i--)
		{
			if ((pRaInfo->RAUseRate)&BIT(i)){
				pRaInfo->HighestRate=i;
				break;
			}
		}
	}
	else{
		pRaInfo->HighestRate=0;
	}
	/*  Lowest rate */
	if (pRaInfo->RAUseRate){
		for (i=0;i<RATESIZE;i++)
		{
			if ((pRaInfo->RAUseRate)&BIT(i))
			{
				pRaInfo->LowestRate=i;
				break;
			}
		}
	}
	else{
		pRaInfo->LowestRate=0;
	}

#if POWER_TRAINING_ACTIVE == 1
		if (pRaInfo->HighestRate >0x13)
			pRaInfo->PTModeSS=3;
		else if (pRaInfo->HighestRate >0x0b)
			pRaInfo->PTModeSS=2;
		else if (pRaInfo->HighestRate >0x0b)
			pRaInfo->PTModeSS=1;
		else
			pRaInfo->PTModeSS=0;
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
				("ODM_ARFBRefresh_8188E(): PTModeSS=%d\n", pRaInfo->PTModeSS));

#endif

	if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
		pRaInfo->DecisionRate = pRaInfo->HighestRate;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
				("ODM_ARFBRefresh_8188E(): RateID=%d RateMask=%8.8x RAUseRate=%8.8x HighestRate=%d,DecisionRate=%d\n",
				pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate,pRaInfo->DecisionRate));
	return 0;
}

#if POWER_TRAINING_ACTIVE == 1
static void
odm_PTTryState_8188E(
		PODM_RA_INFO_T	pRaInfo
	)
{
	pRaInfo->PTTryState=0;
	switch (pRaInfo->PTModeSS)
	{
		case 3:
			if (pRaInfo->DecisionRate>=0x19)
				pRaInfo->PTTryState=1;
			break;
		case 2:
			if (pRaInfo->DecisionRate>=0x11)
				pRaInfo->PTTryState=1;
			break;
		case 1:
			if (pRaInfo->DecisionRate>=0x0a)
				pRaInfo->PTTryState=1;
			break;
		case 0:
			if (pRaInfo->DecisionRate>=0x03)
				pRaInfo->PTTryState=1;
			break;
		default:
			pRaInfo->PTTryState=0;
	}

	if (pRaInfo->RssiStaRA<48)
	{
		pRaInfo->PTStage=0;
	}
	else if (pRaInfo->PTTryState==1)
	{
		if ((pRaInfo->PTStopCount>=10)||(pRaInfo->PTPreRssi>pRaInfo->RssiStaRA+5)
			||(pRaInfo->PTPreRssi<pRaInfo->RssiStaRA-5)||(pRaInfo->DecisionRate!=pRaInfo->PTPreRate))
		{
			if (pRaInfo->PTStage==0)
				pRaInfo->PTStage=1;
			else if (pRaInfo->PTStage==1)
				pRaInfo->PTStage=3;
			else
				pRaInfo->PTStage=5;

			pRaInfo->PTPreRssi=pRaInfo->RssiStaRA;
			pRaInfo->PTStopCount=0;

		}
		else{
			pRaInfo->RAstage=0;
			pRaInfo->PTStopCount++;
		}
	}
	else{
		pRaInfo->PTStage=0;
		pRaInfo->RAstage=0;
	}
	pRaInfo->PTPreRate=pRaInfo->DecisionRate;
}

static void
odm_PTDecision_8188E(
		PODM_RA_INFO_T		pRaInfo
	)
{
	u1Byte j;
	u1Byte temp_stage;
	u4Byte numsc;
	u4Byte num_total;
	u1Byte stage_id;

	numsc  = 0;
	num_total= pRaInfo->TOTAL* PT_PENALTY[5];
	for (j=0;j<=4;j++)
	{
		numsc += pRaInfo->RTY[j] * PT_PENALTY[j];
		if (numsc>num_total)
			break;
	}

	j=j>>1;
	temp_stage= (pRaInfo->PTStage +1)>>1;
	if (temp_stage>j)
		stage_id=temp_stage-j;
	else
		stage_id=0;

	pRaInfo->PTSmoothFactor=(pRaInfo->PTSmoothFactor>>1) + (pRaInfo->PTSmoothFactor>>2) + stage_id*16+2;
	if (pRaInfo->PTSmoothFactor>192)
		pRaInfo->PTSmoothFactor=192;
	stage_id =pRaInfo->PTSmoothFactor>>6;
	temp_stage=stage_id*2;
	if (temp_stage!=0)
		temp_stage-=1;
	if (pRaInfo->DROP>3)
		temp_stage=0;
	pRaInfo->PTStage=temp_stage;

}
#endif

static void
odm_RATxRPTTimerSetting(
		PDM_ODM_T		pDM_Odm,
		u2Byte			minRptTime
)
{
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,(" =====>odm_RATxRPTTimerSetting()\n"));


	if (pDM_Odm->CurrminRptTime != minRptTime){
		ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
		(" CurrminRptTime =0x%04x minRptTime=0x%04x\n", pDM_Odm->CurrminRptTime, minRptTime));
		#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_AP))
		ODM_RA_Set_TxRPT_Time(pDM_Odm,minRptTime);
		#else
		rtw_rpt_timer_cfg_cmd(pDM_Odm->Adapter,minRptTime);
		#endif
		pDM_Odm->CurrminRptTime = minRptTime;
	}
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,(" <=====odm_RATxRPTTimerSetting()\n"));
}


void
ODM_RASupport_Init(
		PDM_ODM_T	pDM_Odm
	)
{
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RASupport_Init()\n"));

	/*  2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! */
	if (pDM_Odm->SupportICType == ODM_RTL8188E)
		pDM_Odm->RaSupport88E = true;

}



int
ODM_RAInfo_Init(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	PODM_RA_INFO_T pRaInfo = &pDM_Odm->RAInfo[MacID];
	#if 1
	u1Byte WirelessMode=0xFF; /* invalid value */
	u1Byte max_rate_idx = 0x13; /* MCS7 */
	if (pDM_Odm->pWirelessMode!=NULL){
		WirelessMode=*(pDM_Odm->pWirelessMode);
	}

	if (WirelessMode != 0xFF ){
		if (WirelessMode & ODM_WM_N24G)
			max_rate_idx = 0x13;
		else if (WirelessMode & ODM_WM_G)
			max_rate_idx = 0x0b;
		else if (WirelessMode & ODM_WM_B)
			max_rate_idx = 0x03;
	}

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
				("ODM_RAInfo_Init(): WirelessMode:0x%08x ,max_raid_idx:0x%02x\n",
				WirelessMode,max_rate_idx));

	pRaInfo->DecisionRate = max_rate_idx;
	pRaInfo->PreRate = max_rate_idx;
	pRaInfo->HighestRate=max_rate_idx;
	#else
	pRaInfo->DecisionRate = 0x13;
	pRaInfo->PreRate = 0x13;
	pRaInfo->HighestRate= 0x13;
	#endif
	pRaInfo->LowestRate=0;
	pRaInfo->RateID=0;
	pRaInfo->RateMask=0xffffffff;
	pRaInfo->RssiStaRA=0;
	pRaInfo->PreRssiStaRA=0;
	pRaInfo->SGIEnable=0;
	pRaInfo->RAUseRate=0xffffffff;
	pRaInfo->NscDown=(N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2;
	pRaInfo->NscUp=(N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2;
	pRaInfo->RateSGI=0;
	pRaInfo->Active=1;	/* Active is not used at present. by page, 110819 */
	pRaInfo->RptTime = 0x927c;
	pRaInfo->DROP=0;
	pRaInfo->RTY[0]=0;
	pRaInfo->RTY[1]=0;
	pRaInfo->RTY[2]=0;
	pRaInfo->RTY[3]=0;
	pRaInfo->RTY[4]=0;
	pRaInfo->TOTAL=0;
	pRaInfo->RAWaitingCounter=0;
	pRaInfo->RAPendingCounter=0;
#if POWER_TRAINING_ACTIVE == 1
	pRaInfo->PTActive=1;   /*  Active when this STA is use */
	pRaInfo->PTTryState=0;
	pRaInfo->PTStage=5; /*  Need to fill into HW_PWR_STATUS */
	pRaInfo->PTSmoothFactor=192;
	pRaInfo->PTStopCount=0;
	pRaInfo->PTPreRate=0;
	pRaInfo->PTPreRssi=0;
	pRaInfo->PTModeSS=0;
	pRaInfo->RAstage=0;
#endif
    return 0;
}

int
ODM_RAInfo_Init_all(
	PDM_ODM_T		pDM_Odm
	)
{
	u1Byte MacID = 0;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n"));
	pDM_Odm->CurrminRptTime = 0;

	for (MacID=0; MacID<ODM_ASSOCIATE_ENTRY_NUM; MacID++)
		ODM_RAInfo_Init(pDM_Odm,MacID);

	return 0;
}


u1Byte
ODM_RA_GetShortGI_8188E(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
)
{
	if ((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM))
		return 0;
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
		("MacID=%d SGI=%d\n", MacID, pDM_Odm->RAInfo[MacID].RateSGI));
	return pDM_Odm->RAInfo[MacID].RateSGI;
}

u1Byte
ODM_RA_GetDecisionRate_8188E(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	u1Byte DecisionRate = 0;

	if ((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM))
		return 0;
	DecisionRate = (pDM_Odm->RAInfo[MacID].DecisionRate);
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
		(" MacID=%d DecisionRate=0x%x\n", MacID, DecisionRate));
	return DecisionRate;
}

u1Byte
ODM_RA_GetHwPwrStatus_8188E(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	u1Byte PTStage = 5;
	if ((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM))
		return 0;
	PTStage = (pDM_Odm->RAInfo[MacID].PTStage);
	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
		("MacID=%d PTStage=0x%x\n", MacID, PTStage));
	return PTStage;
}

void
ODM_RA_UpdateRateInfo_8188E(
	PDM_ODM_T pDM_Odm,
	u1Byte MacID,
	u1Byte RateID,
	u4Byte RateMask,
	u1Byte SGIEnable
	)
{
	PODM_RA_INFO_T pRaInfo = NULL;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
		("MacID=%d RateID=0x%x RateMask=0x%x SGIEnable=%d\n",
		MacID, RateID, RateMask, SGIEnable));
	if ((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM))
		return;

	pRaInfo = &(pDM_Odm->RAInfo[MacID]);
	pRaInfo->RateID = RateID;
	pRaInfo->RateMask = RateMask;
	pRaInfo->SGIEnable = SGIEnable;
	odm_ARFBRefresh_8188E(pDM_Odm, pRaInfo);
}

void
ODM_RA_SetRSSI_8188E(
		PDM_ODM_T		pDM_Odm,
		u1Byte			MacID,
		u1Byte			Rssi
	)
{
	PODM_RA_INFO_T pRaInfo = NULL;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
		(" MacID=%d Rssi=%d\n", MacID, Rssi));
	if ((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM))
		return;

	pRaInfo = &(pDM_Odm->RAInfo[MacID]);
	pRaInfo->RssiStaRA = Rssi;
}

void
ODM_RA_Set_TxRPT_Time(
		PDM_ODM_T		pDM_Odm,
		u2Byte			minRptTime
	)
{
#if (DM_ODM_SUPPORT_TYPE & (ODM_AP))
	if (minRptTime != 0xffff)
#endif
	ODM_Write2Byte(pDM_Odm, REG_TX_RPT_TIME, minRptTime);
}


void
ODM_RA_TxRPT2Handle_8188E(
		PDM_ODM_T		pDM_Odm,
		pu1Byte			TxRPT_Buf,
		u2Byte			TxRPT_Len,
		u4Byte			MacIDValidEntry0,
		u4Byte			MacIDValidEntry1
	)
{
	PODM_RA_INFO_T pRAInfo = NULL;
	u1Byte			MacId = 0;
	pu1Byte			pBuffer = NULL;
	u4Byte			valid = 0, ItemNum = 0;
	u2Byte			minRptTime = 0x927c;

	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RA_TxRPT2Handle_8188E(): valid0=%d valid1=%d BufferLength=%d\n",
		MacIDValidEntry0, MacIDValidEntry1, TxRPT_Len));

	ItemNum = TxRPT_Len >> 3;
	pBuffer = TxRPT_Buf;

	do
	{
		if (MacId >= ASSOCIATE_ENTRY_NUM)
			valid = 0;
		else if (MacId >= 32)
			valid = (1<<(MacId-32)) & MacIDValidEntry1;
		else
			valid = (1<<MacId) & MacIDValidEntry0;

		pRAInfo = &(pDM_Odm->RAInfo[MacId]);
		if (valid)
		{

#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE))
			pRAInfo->RTY[0] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer);
			pRAInfo->RTY[1] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer);
			pRAInfo->RTY[2] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_2(pBuffer);
			pRAInfo->RTY[3] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer);
			pRAInfo->RTY[4] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer);
			pRAInfo->DROP =   (u2Byte)GET_TX_REPORT_TYPE1_DROP_0(pBuffer);
#else
			pRAInfo->RTY[0] = (unsigned short)(pBuffer[1] << 8 | pBuffer[0]);
			pRAInfo->RTY[1] = pBuffer[2];
			pRAInfo->RTY[2] = pBuffer[3];
			pRAInfo->RTY[3] = pBuffer[4];
			pRAInfo->RTY[4] = pBuffer[5];
			pRAInfo->DROP  =  pBuffer[6];
#endif
			pRAInfo->TOTAL = pRAInfo->RTY[0] + \
							  pRAInfo->RTY[1] + \
							  pRAInfo->RTY[2] + \
							  pRAInfo->RTY[3] + \
							  pRAInfo->RTY[4] + \
							  pRAInfo->DROP;
			if (pRAInfo->TOTAL != 0)
			{
				ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
							("macid=%d Total=%d R0=%d R1=%d R2=%d R3=%d R4=%d D0=%d valid0=%x valid1=%x\n",
							MacId,
							pRAInfo->TOTAL,
							pRAInfo->RTY[0],
							pRAInfo->RTY[1],
							pRAInfo->RTY[2],
							pRAInfo->RTY[3],
							pRAInfo->RTY[4],
							pRAInfo->DROP,
							MacIDValidEntry0 ,
							MacIDValidEntry1));
#if POWER_TRAINING_ACTIVE == 1
				if (pRAInfo->PTActive){
					if (pRAInfo->RAstage<5){
						odm_RateDecision_8188E(pDM_Odm,pRAInfo);
					}
					else if (pRAInfo->RAstage==5){  /*  Power training try state */
						odm_PTTryState_8188E(pRAInfo);
					}
					else {/*  RAstage==6 */
						odm_PTDecision_8188E(pRAInfo);
					}

					/*  Stage_RA counter */
					if (pRAInfo->RAstage<=5)
						pRAInfo->RAstage++;
					else
						pRAInfo->RAstage=0;
				}
				else{
					odm_RateDecision_8188E(pDM_Odm,pRAInfo);
				}
#else
				odm_RateDecision_8188E(pDM_Odm, pRAInfo);
#endif

#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
				extern void RTL8188E_SetStationTxRateInfo(PDM_ODM_T, PODM_RA_INFO_T, int);
				RTL8188E_SetStationTxRateInfo(pDM_Odm, pRAInfo, MacId);
#ifdef DETECT_STA_EXISTANCE
				void RTL8188E_DetectSTAExistance(PDM_ODM_T	pDM_Odm, PODM_RA_INFO_T pRAInfo, int MacID);
				RTL8188E_DetectSTAExistance(pDM_Odm, pRAInfo, MacId);
#endif
#endif

				ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
							("macid=%d R0=%d R1=%d R2=%d R3=%d R4=%d drop=%d valid0=%x RateID=%d SGI=%d\n",
							MacId,
							pRAInfo->RTY[0],
							pRAInfo->RTY[1],
							pRAInfo->RTY[2],
							pRAInfo->RTY[3],
							pRAInfo->RTY[4],
							pRAInfo->DROP,
							MacIDValidEntry0,
							pRAInfo->DecisionRate,
							pRAInfo->RateSGI));
			}
			else
				ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL=0!!!!\n"));
		}

		if (minRptTime > pRAInfo->RptTime)
			minRptTime = pRAInfo->RptTime;

		pBuffer += TX_RPT2_ITEM_SIZE;
		MacId++;
	}while (MacId < ItemNum);

        odm_RATxRPTTimerSetting(pDM_Odm,minRptTime);


	ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<===== ODM_RA_TxRPT2Handle_8188E()\n"));
}

#else

static void
odm_RATxRPTTimerSetting(
		PDM_ODM_T		pDM_Odm,
		u2Byte			minRptTime
)
{
	return;
}


void
ODM_RASupport_Init(
		PDM_ODM_T	pDM_Odm
	)
{
	return;
}

int
ODM_RAInfo_Init(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	return 0;
}

int
ODM_RAInfo_Init_all(
	PDM_ODM_T		pDM_Odm
	)
{
	return 0;
}

u1Byte
ODM_RA_GetShortGI_8188E(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	return 0;
}

u1Byte
ODM_RA_GetDecisionRate_8188E(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	return 0;
}
u1Byte
ODM_RA_GetHwPwrStatus_8188E(
		PDM_ODM_T	pDM_Odm,
		u1Byte		MacID
	)
{
	return 0;
}

void
ODM_RA_UpdateRateInfo_8188E(
	PDM_ODM_T pDM_Odm,
	u1Byte MacID,
	u1Byte RateID,
	u4Byte RateMask,
	u1Byte SGIEnable
	)
{
	return;
}

void
ODM_RA_SetRSSI_8188E(
		PDM_ODM_T		pDM_Odm,
		u1Byte			MacID,
		u1Byte			Rssi
	)
{
	return;
}

void
ODM_RA_Set_TxRPT_Time(
		PDM_ODM_T		pDM_Odm,
		u2Byte			minRptTime
	)
{
	return;
}

void
ODM_RA_TxRPT2Handle_8188E(
		PDM_ODM_T		pDM_Odm,
		pu1Byte			TxRPT_Buf,
		u2Byte			TxRPT_Len,
		u4Byte			MacIDValidEntry0,
		u4Byte			MacIDValidEntry1
	)
{
	return;
}

#endif