Files
Linux_Drivers/osdrv/extdrv/wireless/mediatek/mt7603/common/cmm_txbf.c
forum_service 213c880673 add driver of tp、wiegand-gpio and wireless
Change-Id: Ie3c11d9d85cf1a05042f5690ac711856fe8b1ad7
2023-12-22 09:56:05 +08:00

1330 lines
36 KiB
C

/*
***************************************************************************
* Ralink Tech Inc.
* 4F, No. 2 Technology 5th Rd.
* Science-based Industrial Park
* Hsin-chu, Taiwan, R.O.C.
*
* (c) Copyright 2002-2009, Ralink Technology, Inc.
*
* All rights reserved. Ralink's source code is an unpublished work and the
* use of a copyright notice does not imply otherwise. This source code
* contains confidential trade secret material of Ralink Tech. Any attemp
* or participation in deciphering, decoding, reverse engineering or in any
* way altering the source code is stricitly prohibited, unless the prior
* written consent of Ralink Technology, Inc. is obtained.
***************************************************************************
Module Name:
cmm_txbf.c
Abstract:
Tx Beamforming related functions
Revision History:
Who When What
-------- ---------- ----------------------------------------------
Shiang 2009/11/04
*/
#include "rt_config.h"
#ifdef TXBF_SUPPORT
#define ETXBF_PROBE_TIME (RA_INTERVAL-100) /* Wait for Sounding Response will time out 100msec before end of RA interval */
#ifdef MFB_SUPPORT
UCHAR mcsToLowerMcs[] = {
/* originalMfb, newMfb1s, newMfb2s, newMfb3s*/
0, 0, 0, 0,
1, 1, 1, 1,
2, 2, 2, 2,
3, 3, 3, 3,
4, 4, 4, 4,
5, 5, 5, 5,
6, 6, 6, 6,
7, 7, 7, 7,
8, 0, 8, 8,
9, 1, 9, 9,
10, 2, 10, 10,
11, 3, 11, 11,
12, 4, 12, 12,
13, 5, 13, 13,
14, 6, 14, 14,
15, 7, 15, 15,
16, 0, 8, 16,
17, 1, 9, 17,
18, 2, 10, 18,
19, 3, 11, 19,
20, 4, 12, 20,
21, 5, 13, 21,
22, 6, 14, 22,
23, 7, 15, 23,
24, 0, 8, 16,
25, 1, 9, 17,
26, 2, 10, 18,
27, 3, 11, 19,
28, 4, 12, 20,
29, 5, 13, 21,
30, 6, 14, 22,
31, 7, 15, 23,
32, 0, 0, 0,
33, 3, 3, 3,
34, 3, 3, 3,
35, 3, 11, 11,
36, 4, 4, 4,
37, 6, 6, 6,
38, 6, 12, 12,
39, 3, 3, 17,
40, 3, 11, 11,
41, 3, 3, 17,
42, 3, 11, 11,
43, 3, 11, 19,
44, 3, 11, 11,
45, 3, 11, 19,
46, 4, 4, 18,
47, 4, 12, 12,
48, 6, 6, 6,
49, 6, 12, 12,
50, 6, 12, 20,
51, 6, 14, 14,
52, 6, 14, 14,
53, 3, 3, 17,
54, 3, 11, 11,
55, 3, 11, 19,
56, 3, 3, 17,
57, 3, 11, 11,
58, 3, 11, 19,
59, 3, 11, 19,
60, 3, 11, 11,
61, 3, 11, 19,
62, 3, 11, 19,
63, 3, 11, 19,
64, 3, 11, 19,
65, 4, 4, 18,
66, 4, 12, 12,
67, 4, 12, 20,
68, 6, 6, 6,
69, 6, 12, 12,
70, 6, 12, 20,
71, 6, 12, 20,
72, 6, 14, 14,
73, 6, 14, 14,
74, 6, 14, 14,
75, 6, 14, 22,
76, 6, 14, 22
};
#endif /* MFB_SUPPORT */
#ifdef ETXBF_EN_COND3_SUPPORT
UCHAR groupShift[] = {4, 4, 4};
UCHAR groupMethod[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 1, 1, 1,
0, 0, 1, 0, 1, 1, 1, 1};
SHORT groupThrd[] = {-8, 4, 20, 32, 52, 68, 80, 88,
-16, 8, 12, 64, 40, 60, 80, 88,
-24, 12, 12, 96, 40, 60, 80, 88};
UINT dataRate[] = {65, 130, 195, 260, 390, 520, 585, 650,
130, 260, 390, 520, 780, 1040, 1170, 1300,
190, 390, 585, 780, 1170, 1560, 1755, 1950};
#endif /* ETXBF_EN_COND3_SUPPORT */
#if defined(RT2883) || defined(RT3883) || defined(RT3593)
static inline VOID rtmp_asic_etxbf_write_change(
IN RTMP_ADAPTER *pAd,
IN BOOLEAN bWriteEnable)
{
UINT8 byteValue;
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_REG_BF, &byteValue);
if (bWriteEnable)
byteValue |= 0x80;
else
byteValue &= (~0x80);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_REG_BF, byteValue);
}
#endif
VOID rtmp_asic_set_bf(
IN RTMP_ADAPTER *pAd)
{
UINT8 byteValue = 0;
UINT Value32;
#if defined(RT2883) || defined(RT3883) || defined(RT3593)
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_REG_BF, &byteValue);
/* Leave bit3 unchanged. It must be enabled to report BF SNR. */
if (pAd->CommonCfg.RegTransmitSetting.field.ITxBfEn)
byteValue |= 0x20;
else
byteValue &= (~0x20);
if (pAd->CommonCfg.ETxBfEnCond)
byteValue |= 0x90;
else
byteValue &= ~0x90;
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_REG_BF, byteValue);
#endif
#ifdef MT76x2
RTMP_IO_READ32(pAd, PFMU_R1, &Value32);
Value32 &= ~0x330;
if (pAd->CommonCfg.RegTransmitSetting.field.ITxBfEn)
Value32 |= 0x120;
else
Value32 &= (~0x120);
if (pAd->CommonCfg.ETxBfEnCond > 0)
Value32 |= 0x210;
else
Value32 &= ~0x210;
RTMP_IO_WRITE32(pAd, PFMU_R1, Value32);
RTMP_IO_READ32(pAd, PFMU_R0, &Value32);
Value32 &= ~((0x1 << 6) | 0x3);
if (pAd->CommonCfg.RegTransmitSetting.field.ITxBfEn)
Value32 |= ((0x1 << 6) | 0x1);
else
Value32 &= ~((0x1 << 6) | 0x1);
if (pAd->CommonCfg.ETxBfEnCond > 0)
{
Value32 |= (0x1 << 6) | 0x2;
RTMP_IO_WRITE32(pAd, TX_TXBF_CFG_2, 0xFFFFFFFF);
}
else
Value32 &= ~((0x1 << 6) | 0x2);
RTMP_IO_WRITE32(pAd, PFMU_R0, Value32);
#endif
}
/*
TxBFInit - Intialize TxBF fields in pEntry
supportsETxBF - TRUE if client supports ETxBF
*/
VOID TxBFInit(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN BOOLEAN supportsETxBF)
{
pEntry->bfState = READY_FOR_SNDG0;
pEntry->sndgMcs = 0;
pEntry->sndg0Snr0 = 0;
pEntry->sndg0Snr1 = 0;
pEntry->sndg0Snr2 = 0;
pEntry->sndg0Mcs = 0;
#ifdef ETXBF_EN_COND3_SUPPORT
pEntry->sndgRateIdx = 0;
pEntry->sndg0RateIdx = 0;
pEntry->sndg1Mcs = 0;
pEntry->sndg1RateIdx = 0;
pEntry->sndg1Snr0 = 0;
pEntry->sndg1Snr1 = 0;
pEntry->sndg1Snr2 = 0;
pEntry->bf0Mcs = 0;
pEntry->bf0RateIdx = 0;
pEntry->bf1Mcs = 0;
pEntry->bf1RateIdx = 0;
#endif /* EXTBF_EN_COND3_SUPPORT */
pEntry->noSndgCnt = 0;
pEntry->eTxBfEnCond = supportsETxBF? pAd->CommonCfg.ETxBfEnCond: 0;
pEntry->noSndgCntThrd = NO_SNDG_CNT_THRD;
pEntry->ndpSndgStreams = pAd->Antenna.field.TxPath;
/* If client supports ETxBf and ITxBF then give ETxBF priority over ITxBF */
pEntry->iTxBfEn = pEntry->eTxBfEnCond> 0 ? 0 : pAd->CommonCfg.RegTransmitSetting.field.ITxBfEn;
}
BOOLEAN rtmp_chk_itxbf_calibration(
IN RTMP_ADAPTER *pAd)
{
INT calIdx, calCnt;
USHORT offset, eeVal, *calptr;
#ifndef MT76x2
USHORT g_caladdr[] = {0x1a0, 0x1a2, 0x1b0, 0x1b2, 0x1b6, 0x1b8};
USHORT a_caladdr[] = {0x1a4, 0x1a6, 0x1a8, 0x1aa, 0x1ac, 0x1ae, 0x1b4, 0x1ba, 0x1bc, 0x1be, 0x1c0, 0x1c2, 0x1c4, 0x1c6, 0x1c8};
#else
USHORT g_caladdr[] = {0xc0, 0xc2, 0xd4, 0xd6, 0xd8};
USHORT a_caladdr[] = {0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0};
#endif
UINT32 ee_sum;
BOOLEAN bCalibrated = TRUE;
if (pAd->CommonCfg.Channel <= 14)
{
calCnt = sizeof(g_caladdr) / sizeof(USHORT);
calptr = &g_caladdr[0] ;
}
else
{
calCnt = sizeof(a_caladdr) / sizeof(USHORT);
calptr = &a_caladdr[0];
}
ee_sum = 0;
for (calIdx = 0; calIdx < calCnt; calIdx++)
{
offset = *(calptr + calIdx);
RT28xx_EEPROM_READ16(pAd, offset, eeVal);
ee_sum += eeVal;
DBGPRINT(RT_DEBUG_INFO, ("Check EEPROM(offset=0x%x, eeVal=0x%x, ee_sum=0x%x)!\n",
offset, eeVal, ee_sum));
if (eeVal!=0xffff && eeVal!=0)
return TRUE;
}
if ((ee_sum == (0xffff * calCnt)) || (ee_sum == 0x0))
{
bCalibrated = FALSE;
DBGPRINT(RT_DEBUG_TRACE, ("EEPROM all 0xffff(cnt =%d, sum=0x%x), not valid calibration value!\n",
calCnt, ee_sum));
}
return bCalibrated;
}
VOID Trigger_Sounding_Packet(
IN PRTMP_ADAPTER pAd,
IN UCHAR SndgType,
IN UCHAR SndgBW,
IN UCHAR SndgMcs,
IN MAC_TABLE_ENTRY *pEntry)
{
/*
SngType
0: disable
1 : sounding
2: NDP sounding
*/
NdisAcquireSpinLock(&pEntry->TxSndgLock);
pEntry->TxSndgType = SndgType;
NdisReleaseSpinLock(&pEntry->TxSndgLock);
RTMPSetTimer(&pEntry->eTxBfProbeTimer, ETXBF_PROBE_TIME);
/*DBGPRINT(RT_DEBUG_TRACE, ("ETxBF in Trigger_Sounding_Packet(): sndgType=%d, bw=%d, mcs=%d\n", SndgType, SndgBW, SndgMcs)); */
}
/*
eTxBFProbing - called by Rate Adaptation routine each interval.
Initiates a sounding packet if enabled.
*/
VOID eTxBFProbing(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry)
{
if (pEntry->eTxBfEnCond == 0)
{
pEntry->bfState = READY_FOR_SNDG0;
}
else if (pEntry->bfState==READY_FOR_SNDG0 && pEntry->noSndgCnt>=pEntry->noSndgCntThrd)
{
/* Select NDP sounding, maximum streams */
pEntry->sndgMcs = (pEntry->ndpSndgStreams==3) ? 16 : 8;
Trigger_Sounding_Packet(pAd, SNDG_TYPE_NDP, 0, pEntry->sndgMcs, pEntry);
pEntry->bfState = WAIT_SNDG_FB0;
pEntry->noSndgCnt = 0;
}
else if (pEntry->bfState == READY_FOR_SNDG0)
{
pEntry->noSndgCnt++;
}
else
pEntry->noSndgCnt = 0;
}
/*
clientSupportsETxBF - returns true if client supports compatible Sounding
*/
BOOLEAN clientSupportsETxBF(
IN PRTMP_ADAPTER pAd,
IN HT_BF_CAP *pTxBFCap)
{
BOOLEAN compCompat, noncompCompat;
compCompat = (pTxBFCap->ExpComBF > 0) &&
/*(pTxBFCap->ComSteerBFAntSup+1 >= pAd->Antenna.field.TxPath) && */
(pAd->CommonCfg.ETxBfNoncompress == 0);
noncompCompat = (pTxBFCap->ExpNoComBF > 0)
/* && (pTxBFCap->NoComSteerBFAntSup+1 >= pAd->Antenna.field.TxPath)*/;
return pTxBFCap->RxNDPCapable==1 && (compCompat || noncompCompat);
}
#ifdef VHT_TXBF_SUPPORT
/*
clientSupportsETxBF - returns true if client supports compatible Sounding
*/
BOOLEAN clientSupportsVHTETxBF(
IN PRTMP_ADAPTER pAd,
IN VHT_CAP_INFO *pTxBFCap)
{
return pTxBFCap->bfee_cap_su;
}
#endif
/*
setETxBFCap - sets our ETxBF capabilities
*/
void setETxBFCap(RTMP_ADAPTER *pAd, HT_BF_CAP *pTxBFCap)
{
if (pAd->CommonCfg.ETxBfIncapable) {
memset(pTxBFCap, 0, sizeof(*pTxBFCap));
}
else
{
pTxBFCap->RxNDPCapable = TRUE;
pTxBFCap->TxNDPCapable = TRUE;
pTxBFCap->ExpNoComSteerCapable = TRUE;
pTxBFCap->ExpComSteerCapable = !pAd->CommonCfg.ETxBfNoncompress;
pTxBFCap->ExpNoComBF = HT_ExBF_FB_CAP_IMMEDIATE;
pTxBFCap->ExpComBF = pAd->CommonCfg.ETxBfNoncompress? HT_ExBF_FB_CAP_NONE: HT_ExBF_FB_CAP_IMMEDIATE;
pTxBFCap->MinGrouping = 3;
#ifndef MT76x2
pTxBFCap->NoComSteerBFAntSup = 2;
pTxBFCap->ComSteerBFAntSup = 2;
#else
pTxBFCap->NoComSteerBFAntSup = 1; // 2 Tx antenna sounding
pTxBFCap->ComSteerBFAntSup = 1; // 2 Tx antenna sounding
pTxBFCap->TxSoundCapable = TRUE; // Support staggered sounding frames
#endif
pTxBFCap->ChanEstimation = pAd->Antenna.field.RxPath-1;
}
}
#ifdef VHT_TXBF_SUPPORT
void setVHTETxBFCap(RTMP_ADAPTER *pAd, VHT_CAP_INFO *pTxBFCap)
{
if (pAd->CommonCfg.ETxBfIncapable) {
pTxBFCap->num_snd_dimension = 0;
pTxBFCap->bfee_cap_mu = 0;
pTxBFCap->bfee_cap_su = 0;
pTxBFCap->bfer_cap_mu = 0;
pTxBFCap->bfer_cap_su = 0;
pTxBFCap->cmp_st_num_bfer = 0;
}
else
{
pTxBFCap->bfee_cap_su = 1;
pTxBFCap->bfer_cap_su = 1;
pTxBFCap->num_snd_dimension = 1;
pTxBFCap->cmp_st_num_bfer = 1;
}
}
#endif
#ifdef ETXBF_EN_COND3_SUPPORT
/*
4. determine the best method among mfb0, mfb1, snrComb0, snrComb1
5. use the best method. if necessary, sndg with the mcs which resulting in the best snrComb.
*/
/*if mcs is not in group 1 */
VOID txSndgSameMcs(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN UCHAR smoothMfb)/*smoothMfb should be the current mcs */
{
PUCHAR pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx, i, step;
BOOLEAN bWriteEnable;
UCHAR SndgType = SNDG_TYPE_SOUNDING;
if (pEntry->eTxBfEnCond == 0)
{
pEntry->bfState = READY_FOR_SNDG0;
return;
}
/*0. write down the current mfb0 */
pEntry->mfb0 = smoothMfb;
/* 1. sndg with current mcs, get snrComb0 */
if (smoothMfb >> 3 > 0 )
{
pEntry->sndgMcs = smoothMfb;
}
else
{
pEntry->sndgMcs = 8;
SndgType = SNDG_TYPE_NDP;
}
/* if ndp sndg is forced by iwpriv command */
if (pEntry->ndpSndgStreams == 2 ||pEntry->ndpSndgStreams == 3)
{
SndgType = SNDG_TYPE_NDP;
if (pEntry->ndpSndgStreams == 3)
pEntry->sndgMcs = 16;
else
pEntry->sndgMcs = 8;
}
/*
smoothMfb is guaranteed included in the current pTable because
it is converted from received MFB in handleHtcField()
*/
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
#ifdef NEW_RATE_ADAPT_SUPPORT
if (ADAPT_RATE_TABLE(pTable))
step = 10;
else
#endif /* NEW_RATE_ADAPT_SUPPORT */
step = 5;
for (i=1; i<=TableSize; i++)
{
if (pTable[i*step+2] >= pEntry->sndgMcs)
break;
}
if (i > TableSize)
i = TableSize - 1;
/*
DBGPRINT(RT_DEBUG_TRACE, ("txSndgSameMcs i = %x, step = %x, sndgMcs = %x CurrentMCS = %x \n",
i, step, pEntry->sndgMcs, pTable[i*step+2]));
*/
pEntry->sndgRateIdx = pTable[i*step];
if (pEntry->sndgMcs != pTable[i*step+2])
{
/*pEntry->sndgMcs = pTable[i*step+2];*/
if (pTable[i*step+2] > 16)
pEntry->sndgMcs = 16;
else if (pTable[i*step+2] > 8)
pEntry->sndgMcs = 8;
else
pEntry->sndgMcs = 0;
SndgType = SNDG_TYPE_NDP;
}
/* Enable/disable BF matrix writing */
if (pEntry->eTxBfEnCond == 1 || pEntry->eTxBfEnCond == 2)
{
bWriteEnable = TRUE;
pEntry->HTPhyMode.field.eTxBF = 1;
}
else
{
bWriteEnable = FALSE;
}
rtmp_asic_etxbf_write_change(pAd, bWriteEnable);
/* send a sounding packet*/
Trigger_Sounding_Packet(pAd, SndgType, 0, pEntry->sndgMcs, pEntry);
pEntry->bfState = WAIT_SNDG_FB0;
pEntry->noSndgCnt = 0;
}
/*
txSndgOtherGroup - NOTE: currently unused.
Only called when ETxBfEnCond==3
*/
VOID txSndgOtherGroup(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry)
{
PUCHAR pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx, i, step;
UCHAR byteValue = 0;
UCHAR SndgType = SNDG_TYPE_SOUNDING;
/* tx sndg with mcs in the other group */
if ((pEntry->sndgMcs)>>3 == 2)
{
pEntry->sndgMcs = 8;
SndgType = SNDG_TYPE_NDP;
}
else
{
pEntry->sndgMcs = 16;
SndgType = SNDG_TYPE_NDP;
}
/* copied from txSndgSameMcs() */
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
#ifdef NEW_RATE_ADAPT_SUPPORT
if (ADAPT_RATE_TABLE(pTable))
step = 10;
else
#endif /* NEW_RATE_ADAPT_SUPPORT */
step = 5;
for (i=1; i<=TableSize; i++)
{
if (pTable[i*step+2] >= pEntry->sndgMcs) break;
}
if (i > TableSize)
i = TableSize - 1;
pEntry->sndgRateIdx = pTable[i*step];
if (pEntry->sndgMcs != pTable[i*step+2])
{
pEntry->sndgMcs = pTable[i*step+2];
SndgType = SNDG_TYPE_NDP;
}
/*---copied from txSndgSameMcs() end */
/* disable BF matrix writing */
rtmp_asic_etxbf_write_change(pAd, FALSE);
Trigger_Sounding_Packet(pAd, SndgType, 0, pEntry->sndgMcs, pEntry);
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in txSndgOtherGroup(): tx the second SNDG, enter state WAIT_SNDG_FB1\n" ));
pEntry->bfState = WAIT_SNDG_FB1;
}
VOID txMrqInvTxBF(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry)
{
pEntry->toTxMrq = TRUE;
pEntry->msiToTx = MSI_TOGGLE_BF;
/* pEntry->HTPhyMode.field.TxBF = ~pEntry->HTPhyMode.field.TxBF;done in another function call*/
RTMPSetTimer(&pEntry->eTxBfProbeTimer, ETXBF_PROBE_TIME);
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in txMrqInvTxBF(): tx the second MRQ, enter state WAIT_MFB\n" ));
pEntry->bfState = WAIT_MFB;
}
UINT convertSnrToThroughput(
IN UCHAR streamsIn,
IN INT snr0,
IN INT snr1,
IN INT snr2,
IN PUCHAR pTable,
OUT UCHAR *bestMcsPtr,
OUT UCHAR *bestRateIdxPtr
)
{
UCHAR streams;
INT snrTemp;
UCHAR i, j;
SHORT idx;
SHORT group;
INT snrTemp1[3];
INT snr[] = {snr0, snr1, snr2};
INT snrSum, tpTemp, bestTp=0;
SHORT thrdTemp;
BOOLEAN isMcsValid[24];
UCHAR rateIdx[24], step, tableSize;
UCHAR mcs;
#ifdef NEW_RATE_ADAPT_SUPPORT
if (ADAPT_RATE_TABLE(pTable))
step = 10;
else
#endif /* NEW_RATE_ADAPT_SUPPORT */
step = 5;
tableSize = RATE_TABLE_SIZE(pTable);
for (i=0; i<24; i++)
{
isMcsValid[i] = FALSE;
rateIdx[i] = 0;
}
for (i=1; i<=tableSize; i++)
{
isMcsValid[pTable[i*step+2]] = TRUE;
rateIdx[pTable[i*step+2]] = pTable[i*step];
}
if (streamsIn > 3)
{
DBGPRINT(RT_DEBUG_TRACE,("convertSnrToThroughput(): %d streams are not supported!!!", streamsIn));
streams = 3;
}
else
streams = streamsIn;
for (i=0; i<streams; i++){
for (j=i+1; j<streams; j++){
if (snr[i] < snr[j]){
snrTemp = snr[i];
snr[i] = snr[j];
snr[j] = snrTemp;
}
}
}
(*bestMcsPtr) = 0;
(*bestRateIdxPtr) = rateIdx[0];
for (group=streams-1; group >=0; group--)
{
snrTemp1[0] = snr[0];
snrTemp1[1] = snr[1];
snrTemp1[2] = snr[2];
/*SNR processing for each group according to the baseband implementation, for example MRC*/
switch (group)
{
case 0:
snrTemp1[1] = 0;
snrTemp1[2] = 0;
break;
case 1:
snrTemp1[2] = 0;
break;
case 2:
break;
default:
break;
}
snrSum = snr[0] + snr[1] + snr[2];
for (idx=7; idx>=0; idx--){
mcs = group*8+idx;
thrdTemp = groupThrd[mcs];
tpTemp = 0;
if (groupMethod[mcs] == 0)
{
if (snrSum > thrdTemp)
tpTemp = ((snrSum - thrdTemp) * dataRate[mcs])>>groupShift[group];
}
else
{
if (group == 1)
snrTemp1[2] = thrdTemp + 1;
if (snrTemp1[0] > thrdTemp && snrTemp1[1] > thrdTemp && snrTemp1[2] > thrdTemp)
tpTemp = ((snrTemp1[0] - thrdTemp)*(snrTemp1[1] - thrdTemp)*(snrTemp1[2] - thrdTemp) * dataRate[mcs])>>groupShift[group];/* have to be revised!!!*/
}
if (tpTemp > dataRate[mcs])
tpTemp = dataRate[mcs];
if (tpTemp > bestTp && isMcsValid[mcs] == TRUE)
{
bestTp = tpTemp;
(*bestMcsPtr) = mcs;
(*bestRateIdxPtr) = rateIdx[mcs];
DBGPRINT(RT_DEBUG_TRACE,("convertSnrToThroughput(): new candidate snr0=%d, snr1=%d, snr2=%d, tp=%d, best MCS=%d\n", snrTemp1[0], snrTemp1[1], snrTemp1[2], tpTemp, *bestMcsPtr));
}
}
}
DBGPRINT(RT_DEBUG_TRACE,("convertSnrToThroughput(): snr0=%d, snr1=%d, snr2=%d, tp=%d, best MCS=%d\n", snr0, snr1, snr2, bestTp, *bestMcsPtr));
return bestTp;
}
/*
NOTE: currently unused. Only called when ETxBfEnCond==3
*/
VOID chooseBestMethod(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN UCHAR mfb)
{
/* UCHAR bestMethod;0:original, 1:inverted TxBF, 2:first sndg, 3:second sndg*/
UINT tp[4], bestTp;
UCHAR streams, i;
PUCHAR pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx;
UCHAR byteValue = 0;
pEntry->mfb1 = mfb;
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): received the second MFB %d, noted as mfb1\n", pEntry->mfb1 ));
if ((pEntry->HTCapability.MCSSet[2] == 0xff) && (pAd->CommonCfg.TxStream == 3))
{
streams = 3;
}
else if (pEntry->HTCapability.MCSSet[0] == 0xff && pEntry->HTCapability.MCSSet[1] == 0xff && pAd->CommonCfg.TxStream > 1
&& (pAd->CommonCfg.TxStream == 2 || pEntry->HTCapability.MCSSet[2] == 0x0))
{
streams = 2;
}
else
{
streams = 1;
}
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
tp[2] = convertSnrToThroughput(streams, pEntry->sndg0Snr0, pEntry->sndg0Snr1, pEntry->sndg0Snr2, pTable, &(pEntry->bf0Mcs), &(pEntry->bf0RateIdx));
tp[3] = convertSnrToThroughput(streams, pEntry->sndg1Snr0, pEntry->sndg1Snr1, pEntry->sndg1Snr2, pTable, &(pEntry->bf1Mcs), &(pEntry->bf1RateIdx));
tp[0] = dataRate[pEntry->mfb0];
tp[1] = dataRate[pEntry->mfb1];
bestTp = 0;
for (i=0; i<4; i++)
{
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): predicted throughput of method %d = %d\n", i, tp[i] ));
if (tp[i] > bestTp)
{
bestTp = tp[i];
pEntry->bestMethod = i;
}
}
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): method %d is chosen\n", pEntry->bestMethod ));
switch (pEntry->bestMethod)
{
case 0:/*do nothing*/
pEntry->bfState = READY_FOR_SNDG0;
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): do nothing, and enter state READY_FOR_SNDG0\n" ));
break;
case 1:
pEntry->HTPhyMode.field.eTxBF = ~pEntry->HTPhyMode.field.eTxBF;
pEntry->bfState = READY_FOR_SNDG0;
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): invert the ETxBF status, and enter state READY_FOR_SNDG0\n" ));
break;
case 2:
pEntry->sndgMcs = pEntry->sndg0Mcs;
pEntry->sndgRateIdx = pEntry->sndg0RateIdx;
/* enable BF matrix writing */
rtmp_asic_etxbf_write_change(pAd, TRUE);
if (pEntry->sndgRateIdx == pEntry->CurrTxRateIndex)
Trigger_Sounding_Packet(pAd, SNDG_TYPE_SOUNDING, 0, pEntry->sndgMcs, pEntry);
else
Trigger_Sounding_Packet(pAd, SNDG_TYPE_NDP, 0, pEntry->sndgMcs, pEntry);
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): tx the SNDG of the best method, enter state WAIT_BEST_SNDG\n" ));
pEntry->bfState = WAIT_BEST_SNDG;
break;
case 3:
/* tx sndg with mcs in the other group */
pEntry->sndgMcs = pEntry->sndg1Mcs;
pEntry->sndgRateIdx = pEntry->sndg1RateIdx;
/* enable BF matrix writing */
rtmp_asic_etxbf_write_change(pAd, TRUE);
if (pEntry->sndgRateIdx == pEntry->CurrTxRateIndex)
Trigger_Sounding_Packet(pAd, SNDG_TYPE_SOUNDING, 0, pEntry->sndgMcs, pEntry);
else
Trigger_Sounding_Packet(pAd, SNDG_TYPE_NDP, 0, pEntry->sndgMcs, pEntry);
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in chooseBestMethod(): tx the SNDG of the best method, enter state WAIT_BEST_SNDG\n" ));
pEntry->bfState = WAIT_BEST_SNDG;
break;
}
}
/*
NOTE: currently unused. Only called when ETxBfEnCond==3
*/
VOID rxBestSndg(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry)
{
/*set the best mcs of this BF matrix*/
if (pEntry->bestMethod == 2)
{
pEntry->CurrTxRate = pEntry->bf0Mcs;
pEntry->CurrTxRateIndex = pEntry->bf0RateIdx;
}
else if (pEntry->bestMethod == 3)
{
pEntry->CurrTxRate = pEntry->bf1Mcs;
pEntry->CurrTxRateIndex = pEntry->bf1RateIdx;
}
pEntry->HTPhyMode.field.eTxBF = 1;
/*must sync the timing of using new BF matrix and its bfRateIdx!!!*/
/*need to reset counter for rateAdapt and may have to skip one adaptation when the new BF matrix is applied!!!*/
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in rxBestSndg(): received the feedback of the best SNDG, and enter state READY_FOR_SNDG0\n" ));
pEntry->bfState = READY_FOR_SNDG0;
}
#endif /* ETXBF_EN_COND3_SUPPORT */
VOID handleBfFb(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk)
{
MAC_TABLE_ENTRY *pEntry = NULL;
if (pRxBlk->wcid >= MAX_LEN_OF_MAC_TABLE)
return;
pEntry = &(pAd->MacTab.Content[pRxBlk->wcid]);
/*
DBGPRINT(RT_DEBUG_TRACE, ("ETxBF :(%02x:%02x:%02x:%02x:%02x:%02x)\n",
PRINT_MAC(pEntry->Addr)));
*/
if (pEntry->bfState == WAIT_SNDG_FB0)
{
int Nc = ((pRxBlk ->pData)[2] & 0x3) + 1;
/*record the snr comb*/
pEntry->sndg0Snr0 = 88+(CHAR)(pRxBlk ->pData[8]);
pEntry->sndg0Snr1 = (Nc<2)? 0: 88+(CHAR)(pRxBlk ->pData[9]);
pEntry->sndg0Snr2 = (Nc<3)? 0: 88+(CHAR)(pRxBlk ->pData[10]);
pEntry->sndg0Mcs = pEntry->sndgMcs;
DBGPRINT(RT_DEBUG_INFO,(" ETxBF: aid=%d snr %d.%02d %d.%02d %d.%02d\n",
pRxBlk->wcid,
pEntry->sndg0Snr0/4, 25*(pEntry->sndg0Snr0 & 0x3),
pEntry->sndg0Snr1/4, 25*(pEntry->sndg0Snr1 & 0x3),
pEntry->sndg0Snr2/4, 25*(pEntry->sndg0Snr2 & 0x3)) );
#ifdef ETXBF_EN_COND3_SUPPORT
if (pEntry->eTxBfEnCond == 1 ||pEntry->eTxBfEnCond == 2)
pEntry->bfState = READY_FOR_SNDG0;
/* 2. sndg with current mcs+8 or -8, get snrComb1*/
else if (pEntry->eTxBfEnCond == 3)
txSndgOtherGroup(pAd, pEntry);
#else
pEntry->bfState = READY_FOR_SNDG0;
#endif
}
#ifdef ETXBF_EN_COND3_SUPPORT
else if (pEntry->bfState == WAIT_SNDG_FB1)
{
/* 3. mrq with inverted TxBF status, get mfb1*/
if (TRUE)
{
int Nc = ((pRxBlk ->pData)[2] & 0x3) + 1;
/* record the snr comb */
pEntry->sndg1Snr0 = 88+(CHAR)(pRxBlk ->pData[8]);
pEntry->sndg1Snr1 = (Nc<2)? 0: 88+(CHAR)(pRxBlk ->pData[9]);
pEntry->sndg1Snr2 = (Nc<3)? 0: 88+(CHAR)(pRxBlk ->pData[10]);
pEntry->sndg1Mcs = pEntry->sndgMcs;
DBGPRINT(RT_DEBUG_INFO,(" ETxBF: mcs%d, snr %d %d %d\n", pEntry->sndg1Mcs, pEntry->sndg1Snr0, pEntry->sndg1Snr1, pEntry->sndg1Snr2 ));
txMrqInvTxBF(pAd, pEntry);
}
else
chooseBestMethod(pAd, pEntry, 0);
}
else if (pEntry->bfState == WAIT_USELESS_RSP)
{
int Nc = ((pRxBlk ->pData)[2] & 0x3) + 1;
pEntry->sndg0Snr0 = 88+(CHAR)(pRxBlk ->pData[8]);
pEntry->sndg0Snr1 = (Nc<2)? 0: 88+(CHAR)(pRxBlk ->pData[9]);
pEntry->sndg0Snr2 = (Nc<3)? 0: 88+(CHAR)(pRxBlk ->pData[10]);
DBGPRINT(RT_DEBUG_INFO,(" ETxBF: mcs%d, snr %d %d %d\n", pEntry->sndg1Mcs, pEntry->sndg1Snr0, pEntry->sndg1Snr1, pEntry->sndg1Snr2 ));
txSndgSameMcs(pAd, pEntry, /*pRxBlk,*/ pEntry->lastLegalMfb);
}
else if (pEntry->bfState == WAIT_BEST_SNDG)
{
rxBestSndg(pAd, pEntry);
}
#endif /* ETXBF_EN_COND3_SUPPORT */
}
VOID handleHtcField(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk)
{
#ifdef MFB_SUPPORT
UCHAR mfb = ((PHT_CONTROL)(pRxBlk->pData))-> MFBorASC;
UCHAR mfsi = ((PHT_CONTROL)(pRxBlk->pData))-> MFSI;
UCHAR legalMfb = 0, legalMfbIdx=0, smoothMfb = 0;
MAC_TABLE_ENTRY *pEntry = NULL;
UCHAR i, j;
UCHAR *pTable;
UCHAR TableSize = 0;
UCHAR InitTxRateIdx;
UCHAR snr[] = {pRxBlk->rx_signal.raw_snr[0], pRxBlk->rx_signal.raw_snr[1], pRxBlk->rx_signal.raw_snr[2]};
UCHAR snrTemp1[3];
UCHAR snrTemp;
UCHAR streams;
UINT tpTemp, bestTp = 0, snrSum;
SHORT thrdTemp;
SHORT group, idx;
UCHAR mcs;
RTMP_RA_GRP_TB *pLegalMfbRS3S = NULL;
RTMP_RA_LEGACY_TB *pLegalMfbRS = NULL;
if (pRxBlk->wcid >= MAX_LEN_OF_MAC_TABLE)
{
return;
}
pEntry = &(pAd->MacTab.Content[pRxBlk->wcid]);
/* if MFB is received, have to rule out the case when mai==14 */
if (!(((PHT_CONTROL)(pRxBlk->pData))->MRQ == 0 && ((PHT_CONTROL)(pRxBlk->pData))->MSI == 7)
&& mfb != 127)
{/* need a timer in case there is no mfb with this mfsi */
DBGPRINT(RT_DEBUG_INFO, (" MFB in handleHtcField(): MFB %d is received\n", mfb));
/* check if the mfb is valid. if not, convert to a valid mcs */
if (mfb > 76)
DBGPRINT(RT_DEBUG_TRACE, ("Error in handleHtcField: received MFB > 76\n"));
if (pEntry->HTCapability.MCSSet[0] == 0xff && pEntry->HTCapability.MCSSet[1] == 0xff
&& pEntry->HTCapability.MCSSet[2] == 0xff && pAd->CommonCfg.TxStream == 3)
legalMfb = mcsToLowerMcs[4*mfb + 3];
else if (pEntry->HTCapability.MCSSet[0] == 0xff && pEntry->HTCapability.MCSSet[1] == 0xff && pAd->CommonCfg.TxStream > 1
&& (pAd->CommonCfg.TxStream == 2 || pEntry->HTCapability.MCSSet[2] == 0x0))
legalMfb = mcsToLowerMcs[4*mfb + 2];
else if (pEntry->HTCapability.MCSSet[0] == 0xff &&( pAd->CommonCfg.TxStream == 1 ||pEntry->HTCapability.MCSSet[1] == 0x0))
legalMfb = mcsToLowerMcs[4*mfb + 1];
else
DBGPRINT(RT_DEBUG_TRACE, ("no available MFB mapping for the received MFB\n"));
/*
have to rule out the mfb that the Rx shouldn't be able to suggest???
for example, mrq was sent with 2 streams but the Rx suggests MCS
with 3 streams
*/
#ifdef ETXBF_EN_COND3_SUPPORT
if (mfsi == MSI_TOGGLE_BF)
{
if (pEntry->bfState == WAIT_MFB)
chooseBestMethod(pAd, pEntry, legalMfb);
else if (pEntry->bfState == WAIT_USELESS_RSP)
txSndgSameMcs(pAd, pEntry,/* pRxBlk,*/ legalMfb);
}
#endif
}
if (!(((PHT_CONTROL)(pRxBlk->pData))->MRQ == 0 && ((PHT_CONTROL)(pRxBlk->pData))->MSI == 7 && mfsi != MSI_TOGGLE_BF)
&& mfb != 127)
{
/* the main body of algorithm */
/* legalMfb smoothing */
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);
#ifdef NEW_RATE_ADAPT_SUPPORT
if (ADAPT_RATE_TABLE(pTable))
{
for (i=1; i<=RATE_TABLE_SIZE(pTable); i++)
{
if (legalMfb == pTable[i*10+2])
{
legalMfbIdx = pTable[i*10];
pLegalMfbRS3S = (RTMP_RA_GRP_TB *) &pTable[i*10];
pLegalMfbRS = (RTMP_RA_LEGACY_TB *) &pTable[i*10];
break;
}
}
/* pLegalMfbRS3S may be null if pLegalMfbRS3S is not found!!! */
if (pEntry->lastLegalMfb == pTable[(pLegalMfbRS3S->downMcs+1)*10+2] ||pEntry->lastLegalMfb == pTable[(pLegalMfbRS3S->upMcs1+1)*10+2]
||pEntry->lastLegalMfb == pTable[(pLegalMfbRS3S->upMcs2+1)*10+2] ||pEntry->lastLegalMfb == pTable[(pLegalMfbRS3S->upMcs3+1)*10+2])
smoothMfb = pEntry->lastLegalMfb;
else
smoothMfb = legalMfb;
}
else
#endif /* NEW_RATE_ADAPT_SUPPORT */
{
for (i=1; i<=RATE_TABLE_SIZE(pTable); i++)
{
if (legalMfb == pTable[i*5+2])
{
legalMfbIdx = pTable[i*5];
pLegalMfbRS = (RTMP_RA_LEGACY_TB *) &pTable[i*5];
break;
}
}
if ((pEntry->lastLegalMfb <= legalMfb+1 || pEntry->lastLegalMfb+1 >= legalMfb) && ((legalMfb>>3) == (pEntry->lastLegalMfb >>3)))
smoothMfb = pEntry->lastLegalMfb;
else
smoothMfb = legalMfb;
}
if (smoothMfb != pEntry->lastLegalMfb && smoothMfb != pTable[(pEntry->CurrTxRateIndex+1)*10+2])
{/* if mfb changes and mfb is different from current mcs: means channel change */
#ifdef NEW_RATE_ADAPT_SUPPORT
if ((ADAPT_RATE_TABLE(pTable)))
MlmeSetMcsGroup(pAd, pEntry);
#endif /* NEW_RATE_ADAPT_SUPPORT */
pEntry->CurrTxRateIndex = legalMfbIdx;
MlmeClearTxQuality(pEntry);/* clear all history, same as train up, purpose??? */
NdisAcquireSpinLock(&pEntry->fLastChangeAccordingMfbLock);
NdisMoveMemory(pEntry->LegalMfbRS, pLegalMfbRS, sizeof(RTMP_RA_LEGACY_TB));
pEntry->fLastChangeAccordingMfb = TRUE;
/* reset all OneSecTx counters */
/* RESET_ONE_SEC_TX_CNT(pEntry); */
NdisReleaseSpinLock(&pEntry->fLastChangeAccordingMfbLock);
DBGPRINT(RT_DEBUG_INFO,(" MFB in handleHtcField(): MFB changes and use the new mfb=%d, mfbIdx=%d\n", legalMfb, legalMfbIdx));
/* pEntry->isMfbChanged = TRUE; */
if ((pEntry->HTCapability.TxBFCap.ExpNoComBF && pAd->CommonCfg.HtCapability.TxBFCap.TxSoundCapable
&& pAd->CommonCfg.HtCapability.TxBFCap.ExpNoComSteerCapable))
{/* support ETxBF. what's the correct criterion???? */
/* the process is triggered by channel change here. have to add the mechanism where the process is triggered by timer expiration!!! */
#ifdef ETXBF_EN_COND3_SUPPORT
if (pEntry->eTxBfEnCond == 3)
{
if (pEntry->bfState == READY_FOR_SNDG0)
{
DBGPRINT(RT_DEBUG_OFF,("ETxBF in handleHtcField(): detect MFB change, set pEntry->mfb0=%d\n", pEntry->mfb0 ));
txSndgSameMcs(pAd, pEntry, /*pRxBlk,*/ legalMfb);
}
else
{
DBGPRINT(RT_DEBUG_TRACE,("ETxBF in handleHtcField(): detect channel change before enter the ETxBF probe process is complete, enter state WAIT_USELESS_RSP\n" ));
pEntry->bfState = WAIT_USELESS_RSP;
}
}
#endif
/* write down the current MFB and ixTxBF. currentMFB is recorded in lastLegalMfb */
/* send one packet with reverse TxBF, 2 stream sounding */
}
}
/* post-prossessing */
if (pEntry->fLastChangeAccordingMfb)
pEntry->lastLegalMfb = legalMfb;
}
/*if mrq is received*/
if (((PHT_CONTROL)(pRxBlk->pData))->MRQ == 1)
{
DBGPRINT(RT_DEBUG_INFO, (" MFB in handleHtcField(): MRQ is received\n"));
/*
Assumption:
snr are not sorted, wait for John or Julian's answer as to
the SNR values of unused streams
*/
if ((pEntry->HTCapability.MCSSet[2] == 0xff && pAd->CommonCfg.TxStream == 3))
{
streams = 3;
}
else if (pEntry->HTCapability.MCSSet[0] == 0xff && pEntry->HTCapability.MCSSet[1] == 0xff && pAd->CommonCfg.TxStream > 1
&& (pAd->CommonCfg.TxStream == 2 || pEntry->HTCapability.MCSSet[2] == 0x0))
{
streams = 2;
}
else
{
streams = 1;
}
/*sort such that snr[0]>=snr[1]>=snr[2]. sorting is required for group 2 so that the best 2 streams are used.*/
for (i=0; i<streams; i++)
{
for (j=i+1; j<streams; j++)
{
if (snr[i] < snr[j])
{
snrTemp = snr[i];
snr[i] = snr[j];
snr[j] = snrTemp;
}
}
}
for (group=streams-1; group >=0; group--)
{
snrTemp1[0] = snr[0];
snrTemp1[1] = snr[1];
snrTemp1[2] = snr[2];
/*SNR processing for each group according to the baseband implementation, for example MRC*/
switch (group)
{
case 0:
snrTemp1[1] = 0;
snrTemp1[2] = 0;
break;
case 1:
snrTemp1[2] = 0;
break;
case 2:
break;
default:
break;
}
snrSum = snr[0] + snr[1] + snr[2];
for (idx=8; idx>=1; idx--){
mcs = group*8+idx-1;
thrdTemp = groupThrd[mcs];
tpTemp = 0;
if (groupMethod[mcs] == 0)
{
if (snrSum > thrdTemp)
tpTemp = ((snrSum - thrdTemp) * dataRate[mcs])>>groupShift[group];
}
else
{
if (group == 1)
snrTemp1[2] = thrdTemp + 1;
if (snrTemp1[0] > thrdTemp && snrTemp1[1] > thrdTemp && snrTemp1[2] > thrdTemp)
tpTemp = ((snrTemp1[0] - thrdTemp)*(snrTemp1[1] - thrdTemp)*(snrTemp1[2] - thrdTemp) * dataRate[mcs])>>groupShift[group];/* have to be revised!!! */
}
if (tpTemp > dataRate[mcs])
tpTemp = dataRate[mcs];
if (tpTemp > bestTp)
{
bestTp = tpTemp;
pEntry->mfbToTx = mcs;
}
}
}
pEntry->toTxMfb = 1;/*should be reset to 0 when mfb is actually sent out!!!*/
DBGPRINT(RT_DEBUG_INFO,(" MFB in handleHtcField(): MFB %d is going to be sent\n", pEntry->mfbToTx));
}
#endif /* MFB_SUPPORT */
}
void eTxBfProbeTimerExec(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
MAC_TABLE_ENTRY *pEntry = (PMAC_TABLE_ENTRY) FunctionContext;
#ifdef ETXBF_EN_COND3_SUPPORT
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)pEntry->pAd;
#endif
if (pEntry->bfState == WAIT_SNDG_FB0)
{
/*record the snr comb*/
pEntry->sndg0Snr0 = -128;
pEntry->sndg0Snr1 = -128;
pEntry->sndg0Snr2 = -128;
pEntry->sndg0Mcs = pEntry->sndgMcs;
DBGPRINT(RT_DEBUG_TRACE,(" ETxBF: timer of WAIT_SNDG_FB0 expires\n" ));
#ifdef ETXBF_EN_COND3_SUPPORT
if (pEntry->eTxBfEnCond == 1 || pEntry->eTxBfEnCond == 2)
pEntry->bfState =READY_FOR_SNDG0;
else if (pEntry->eTxBfEnCond == 3)
txSndgOtherGroup(pAd, pEntry);
#else
pEntry->bfState =READY_FOR_SNDG0;
#endif
}
#ifdef ETXBF_EN_COND3_SUPPORT
else if (pEntry->bfState == WAIT_SNDG_FB1)
{
/*record the snr comb*/
pEntry->sndg1Snr0 = -128;
pEntry->sndg1Snr1 = -128;
pEntry->sndg1Snr2 = -128;
pEntry->sndg1Mcs = pEntry->sndgMcs;
DBGPRINT(RT_DEBUG_TRACE,(" ETxBF: timer of WAIT_SNDG_FB1 expires, run txMrqInvTxBF()\n" ));
txMrqInvTxBF(pAd, pEntry);
}
else if (pEntry->bfState == WAIT_MFB)
{
DBGPRINT(RT_DEBUG_TRACE,(" ETxBF: timer of WAIT_MFB expires, run chooseBestMethod()\n" ));
chooseBestMethod(pAd, pEntry, 0);
}
else if (pEntry->bfState == WAIT_BEST_SNDG)
{
DBGPRINT(RT_DEBUG_TRACE,(" ETxBF: timer of WAIT_BEST_SNDG expires, run rxBestSndg()\n" ));
rxBestSndg(pAd, pEntry);
}
#endif /* ETXBF_EN_COND3_SUPPORT */
}
#ifdef MFB_SUPPORT
VOID MFB_PerPareMRQ(
IN PRTMP_ADAPTER pAd,
OUT VOID* pBuf,
IN PMAC_TABLE_ENTRY pEntry)
{
PHT_CONTROL pHT_Control;
/* DBGPRINT(RT_DEBUG_TRACE, ("-----> MFB_PerPareMRQ\n"));*/
if (pEntry->HTCapability.ExtHtCapInfo.MCSFeedback >= MCSFBK_MRQ)
{
pHT_Control = (HT_CONTROL *)pBuf;
pHT_Control->MRQ = 1;
if (pEntry->msiToTx == MSI_TOGGLE_BF) {
if (pEntry->mrqCnt == 0)
pEntry->mrqCnt = TOGGLE_BF_PKTS;
else
{
(pEntry->mrqCnt)--;
if (pEntry->mrqCnt == 0)
pEntry->msiToTx = 0;
}
}
pHT_Control->MSI = pEntry->msiToTx;
/*update region*/
if (pEntry->msiToTx == MSI_TOGGLE_BF-1)/*MSI_TOGGLE_BF==6 is used to indicate the TxBF status is inverted for this packet*/
pEntry->msiToTx = 0;
else if (pEntry->msiToTx != MSI_TOGGLE_BF)
pEntry->msiToTx++;
}
/* DBGPRINT(RT_DEBUG_TRACE, ("<----- MFB_PerPareMRQ\n"));*/
}
/*
Need to be completed!!!!!!!!!!!!!!!!!
*/
VOID MFB_PerPareMFB(
IN PRTMP_ADAPTER pAd,
OUT VOID* pBuf,
IN PMAC_TABLE_ENTRY pEntry)
{
/* DBGPRINT(RT_DEBUG_TRACE, ("-----> MFB_PerPareMRQ\n")); */
#if 0
if (pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback >= MCSFBK_MRQ)
{
PHT_CONTROL pHT_Control = (HT_CONTROL *)pBuf;
pHT_Control-> = 1;
if (pEntry->msiToTx == MSI_TOGGLE_BF)
if (pEntry->mrqCnt == 0)
pEntry->mrqCnt = TOGGLE_BF_PKTS;
else
{
(pEntry->mrqCnt)--;
if (pEntry->mrqCnt == 0)
pEntry->msiToTx = 0;
}
pHT_Control->MFBorASC = ;
pHT_Control->MFSI =
/*update region*/
if (pEntry->msiToTx == MSI_TOGGLE_BF-1)/*MSI_TOGGLE_BF==6 is used to indicate the TxBF status is inverted for this packet*/
pEntry->msiToTx = 0;
else if (pEntry->msiToTx != MSI_TOGGLE_BF)
pEntry->msiToTx++;
}
#endif
/* DBGPRINT(RT_DEBUG_TRACE, ("<----- MFB_PerPareMRQ\n"));*/
}
#endif /* MFB_SUPPORT */
/* MlmeTxBfAllowed - returns true if ETxBF or ITxBF is supported and pTxRate is a valid BF mode */
BOOLEAN MlmeTxBfAllowed(
IN RTMP_ADAPTER *pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN RTMP_RA_LEGACY_TB *pTxRate)
{
/* ETxBF */
if ((pEntry->eTxBfEnCond > 0) &&
(pTxRate->Mode == MODE_HTMIX || pTxRate->Mode == MODE_HTGREENFIELD)
#ifdef DBG_CTRL_SUPPORT
&& (!((pAd->CommonCfg.DebugFlags & DBF_NO_TXBF_3SS) && pTxRate->CurrMCS>20))
#endif /* DBG_CTRL_SUPPORT */
)
return TRUE;
/* ITxBF */
if (pEntry->iTxBfEn && pTxRate->CurrMCS<16 && pTxRate->Mode!=MODE_CCK)
return TRUE;
return FALSE;
}
#endif /* TXBF_SUPPORT */