1330 lines
36 KiB
C
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 */
|
|
|