rtl8192eu-linux-driver/hal/phydm/phydm_beamforming.c
2017-05-11 20:49:39 +02:00

1940 lines
62 KiB
C
Raw Blame History

#include "mp_precomp.h"
#include "phydm_precomp.h"
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
#if WPP_SOFTWARE_TRACE
#include "phydm_beamforming.tmh"
#endif
#endif
#if (BEAMFORMING_SUPPORT == 1)
PRT_BEAMFORM_STAINFO
phydm_staInfoInit(
IN PDM_ODM_T pDM_Odm,
IN u2Byte staIdx
)
{
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PRT_BEAMFORM_STAINFO pEntry = &(pBeamInfo->BeamformSTAinfo);
PSTA_INFO_T pSTA = pDM_Odm->pODM_StaInfo[staIdx];
PADAPTER Adapter = pDM_Odm->Adapter;
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
PMGNT_INFO pMgntInfo = &Adapter->MgntInfo;
PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo);
PRT_VERY_HIGH_THROUGHPUT pVHTInfo = GET_VHT_INFO(pMgntInfo);
ODM_MoveMemory(pDM_Odm, pEntry->MyMacAddr, Adapter->CurrentAddress, 6);
pEntry->HtBeamformCap = pHTInfo->HtBeamformCap;
pEntry->VhtBeamformCap = pVHTInfo->VhtBeamformCap;
/*IBSS, AP mode*/
if (staIdx != 0) {
pEntry->AID = pSTA->AID;
pEntry->RA = pSTA->MacAddr;
pEntry->MacID = pSTA->AssociatedMacId;
pEntry->WirelessMode = pSTA->WirelessMode;
pEntry->BW = pSTA->BandWidth;
pEntry->CurBeamform = pSTA->HTInfo.HtCurBeamform;
} else {/*client mode*/
pEntry->AID = pMgntInfo->mAId;
pEntry->RA = pMgntInfo->Bssid;
pEntry->MacID = pMgntInfo->mMacId;
pEntry->WirelessMode = pMgntInfo->dot11CurrentWirelessMode;
pEntry->BW = pMgntInfo->dot11CurrentChannelBandWidth;
pEntry->CurBeamform = pHTInfo->HtCurBeamform;
}
if ((pEntry->WirelessMode & WIRELESS_MODE_AC_5G) || (pEntry->WirelessMode & WIRELESS_MODE_AC_24G)) {
if (staIdx != 0)
pEntry->CurBeamformVHT = pSTA->VHTInfo.VhtCurBeamform;
else
pEntry->CurBeamformVHT = pVHTInfo->VhtCurBeamform;
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("pSTA->wireless_mode = 0x%x, staidx = %d\n", pSTA->WirelessMode, staIdx));
#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
if (!IS_STA_VALID(pSTA)) {
rtw_warn_on(1);
DBG_871X("%s => sta_info(mac_id:%d) failed\n", __func__, staIdx);
return pEntry;
}
ODM_MoveMemory(pDM_Odm, pEntry->MyMacAddr, adapter_mac_addr(pSTA->padapter), 6);
pEntry->HtBeamformCap = pSTA->htpriv.beamform_cap;
pEntry->AID = pSTA->aid;
pEntry->RA = pSTA->hwaddr;
pEntry->MacID = pSTA->mac_id;
pEntry->WirelessMode = pSTA->wireless_mode;
pEntry->BW = pSTA->bw_mode;
pEntry->CurBeamform = pSTA->htpriv.beamform_cap;
#if ODM_IC_11AC_SERIES_SUPPORT
if ((pEntry->WirelessMode & WIRELESS_MODE_AC_5G) || (pEntry->WirelessMode & WIRELESS_MODE_AC_24G)) {
pEntry->CurBeamformVHT = pSTA->vhtpriv.beamform_cap;
pEntry->VhtBeamformCap = pSTA->vhtpriv.beamform_cap;
}
#endif
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("pSTA->wireless_mode = 0x%x, staidx = %d\n", pSTA->wireless_mode, staIdx));
#endif
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("pEntry->CurBeamform = 0x%x, pEntry->CurBeamformVHT = 0x%x\n", pEntry->CurBeamform, pEntry->CurBeamformVHT));
return pEntry;
}
void phydm_staInfoUpdate(
IN PDM_ODM_T pDM_Odm,
IN u2Byte staIdx,
PRT_BEAMFORMEE_ENTRY pBeamformEntry
)
{
PSTA_INFO_T pSTA = pDM_Odm->pODM_StaInfo[staIdx];
if (!IS_STA_VALID(pSTA))
return;
#if (DM_ODM_SUPPORT_TYPE == ODM_CE)
pSTA->txbf_paid = pBeamformEntry->P_AID;
pSTA->txbf_gid = pBeamformEntry->G_ID;
#endif
}
u1Byte
Beamforming_GetHTNDPTxRate(
IN PVOID pDM_VOID,
u1Byte CompSteeringNumofBFer
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Nr_index = 0;
u1Byte NDPTxRate;
/*Find Nr*/
if (pDM_Odm->SupportICType & ODM_RTL8814A)
Nr_index = TxBF_Nr(halTxbf8814A_GetNtx(pDM_Odm), CompSteeringNumofBFer);
else
Nr_index = TxBF_Nr(1, CompSteeringNumofBFer);
switch (Nr_index) {
case 1:
NDPTxRate = MGN_MCS8;
break;
case 2:
NDPTxRate = MGN_MCS16;
break;
case 3:
NDPTxRate = MGN_MCS24;
break;
default:
NDPTxRate = MGN_MCS8;
break;
}
return NDPTxRate;
}
u1Byte
Beamforming_GetVHTNDPTxRate(
IN PVOID pDM_VOID,
u1Byte CompSteeringNumofBFer
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Nr_index = 0;
u1Byte NDPTxRate;
/*Find Nr*/
if (pDM_Odm->SupportICType & ODM_RTL8814A)
Nr_index = TxBF_Nr(halTxbf8814A_GetNtx(pDM_Odm), CompSteeringNumofBFer);
else
Nr_index = TxBF_Nr(1, CompSteeringNumofBFer);
switch (Nr_index) {
case 1:
NDPTxRate = MGN_VHT2SS_MCS0;
break;
case 2:
NDPTxRate = MGN_VHT3SS_MCS0;
break;
case 3:
NDPTxRate = MGN_VHT4SS_MCS0;
break;
default:
NDPTxRate = MGN_VHT2SS_MCS0;
break;
}
return NDPTxRate;
}
PRT_BEAMFORMEE_ENTRY
phydm_Beamforming_GetBFeeEntryByAddr(
IN PVOID pDM_VOID,
IN pu1Byte RA,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte i = 0;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformeeEntry[i].bUsed && (eqMacAddr(RA, pBeamInfo->BeamformeeEntry[i].MacAddr))) {
*Idx = i;
return &(pBeamInfo->BeamformeeEntry[i]);
}
}
return NULL;
}
PRT_BEAMFORMER_ENTRY
phydm_Beamforming_GetBFerEntryByAddr(
IN PVOID pDM_VOID,
IN pu1Byte TA,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte i = 0;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformerEntry[i].bUsed && (eqMacAddr(TA, pBeamInfo->BeamformerEntry[i].MacAddr))) {
*Idx = i;
return &(pBeamInfo->BeamformerEntry[i]);
}
}
return NULL;
}
PRT_BEAMFORMEE_ENTRY
phydm_Beamforming_GetEntryByMacId(
IN PVOID pDM_VOID,
IN u1Byte MacId,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte i = 0;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformeeEntry[i].bUsed && (MacId == pBeamInfo->BeamformeeEntry[i].MacId)) {
*Idx = i;
return &(pBeamInfo->BeamformeeEntry[i]);
}
}
return NULL;
}
BEAMFORMING_CAP
phydm_Beamforming_GetEntryBeamCapByMacId(
IN PVOID pDM_VOID,
IN u1Byte MacId
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte i = 0;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
BEAMFORMING_CAP BeamformEntryCap = BEAMFORMING_CAP_NONE;
for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformeeEntry[i].bUsed && (MacId == pBeamInfo->BeamformeeEntry[i].MacId)) {
BeamformEntryCap = pBeamInfo->BeamformeeEntry[i].BeamformEntryCap;
i = BEAMFORMEE_ENTRY_NUM;
}
}
return BeamformEntryCap;
}
PRT_BEAMFORMEE_ENTRY
phydm_Beamforming_GetFreeBFeeEntry(
IN PVOID pDM_VOID,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte i = 0;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformeeEntry[i].bUsed == FALSE) {
*Idx = i;
return &(pBeamInfo->BeamformeeEntry[i]);
}
}
return NULL;
}
PRT_BEAMFORMER_ENTRY
phydm_Beamforming_GetFreeBFerEntry(
IN PVOID pDM_VOID,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte i = 0;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s ===>\n", __func__));
for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformerEntry[i].bUsed == FALSE) {
*Idx = i;
return &(pBeamInfo->BeamformerEntry[i]);
}
}
return NULL;
}
/*
// Description: Get the first entry index of MU Beamformee.
//
// Return Value: Index of the first MU sta.
//
// 2015.05.25. Created by tynli.
//
*/
u1Byte
phydm_Beamforming_GetFirstMUBFeeEntryIdx(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte idx = 0xFF;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
BOOLEAN bFound = FALSE;
for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
if (pBeamInfo->BeamformeeEntry[idx].bUsed && pBeamInfo->BeamformeeEntry[idx].is_mu_sta) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] idx=%d!\n", __func__, idx));
bFound = TRUE;
break;
}
}
if (!bFound)
idx = 0xFF;
return idx;
}
/*Add SU BFee and MU BFee*/
PRT_BEAMFORMEE_ENTRY
Beamforming_AddBFeeEntry(
IN PVOID pDM_VOID,
IN PRT_BEAMFORM_STAINFO pSTA,
IN BEAMFORMING_CAP BeamformCap,
IN u1Byte NumofSoundingDim,
IN u1Byte CompSteeringNumofBFer,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMEE_ENTRY pEntry = phydm_Beamforming_GetFreeBFeeEntry(pDM_Odm, Idx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (pEntry != NULL) {
pEntry->bUsed = TRUE;
pEntry->AID = pSTA->AID;
pEntry->MacId = pSTA->MacID;
pEntry->SoundBW = pSTA->BW;
ODM_MoveMemory(pDM_Odm, pEntry->MyMacAddr, pSTA->MyMacAddr, 6);
if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP)) {
/*BSSID[44:47] xor BSSID[40:43]*/
u2Byte BSSID = ((pSTA->MyMacAddr[5] & 0xf0) >> 4) ^ (pSTA->MyMacAddr[5] & 0xf);
/*(dec(A) + dec(B)*32) mod 512*/
pEntry->P_AID = (pSTA->AID + BSSID * 32) & 0x1ff;
pEntry->G_ID = 63;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BFee P_AID addressed to STA=%d\n", __func__, pEntry->P_AID));
} else if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_IBSS)) {
/*ad hoc mode*/
pEntry->P_AID = 0;
pEntry->G_ID = 63;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BFee P_AID as IBSS=%d\n", __func__, pEntry->P_AID));
} else {
/*client mode*/
pEntry->P_AID = pSTA->RA[5];
/*BSSID[39:47]*/
pEntry->P_AID = (pEntry->P_AID << 1) | (pSTA->RA[4] >> 7);
pEntry->G_ID = 0;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BFee P_AID addressed to AP=0x%X\n", __func__, pEntry->P_AID));
}
cpMacAddr(pEntry->MacAddr, pSTA->RA);
pEntry->bTxBF = FALSE;
pEntry->bSound = FALSE;
pEntry->SoundPeriod = 400;
pEntry->BeamformEntryCap = BeamformCap;
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
/* pEntry->LogSeq = 0xff; Move to Beamforming_AddBFerEntry*/
/* pEntry->LogRetryCnt = 0; Move to Beamforming_AddBFerEntry*/
/* pEntry->LogSuccessCnt = 0; Move to Beamforming_AddBFerEntry*/
pEntry->LogStatusFailCnt = 0;
pEntry->NumofSoundingDim = NumofSoundingDim;
pEntry->CompSteeringNumofBFer = CompSteeringNumofBFer;
if (BeamformCap & BEAMFORMER_CAP_VHT_MU) {
pDM_Odm->BeamformingInfo.beamformee_mu_cnt += 1;
pEntry->is_mu_sta = TRUE;
pDM_Odm->BeamformingInfo.FirstMUBFeeIndex = phydm_Beamforming_GetFirstMUBFeeEntryIdx(pDM_Odm);
} else if (BeamformCap & BEAMFORMER_CAP_VHT_SU) {
pDM_Odm->BeamformingInfo.beamformee_su_cnt += 1;
pEntry->is_mu_sta = FALSE;
}
return pEntry;
}
else
return NULL;
}
/*Add SU BFee and MU BFer*/
PRT_BEAMFORMER_ENTRY
Beamforming_AddBFerEntry(
IN PVOID pDM_VOID,
IN PRT_BEAMFORM_STAINFO pSTA,
IN BEAMFORMING_CAP BeamformCap,
IN u1Byte NumofSoundingDim,
OUT pu1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMER_ENTRY pEntry = phydm_Beamforming_GetFreeBFerEntry(pDM_Odm, Idx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (pEntry != NULL) {
pEntry->bUsed = TRUE;
ODM_MoveMemory(pDM_Odm, pEntry->MyMacAddr, pSTA->MyMacAddr, 6);
if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP)) {
/*BSSID[44:47] xor BSSID[40:43]*/
u2Byte BSSID = ((pSTA->MyMacAddr[5] & 0xf0) >> 4) ^ (pSTA->MyMacAddr[5] & 0xf);
pEntry->P_AID = (pSTA->AID + BSSID * 32) & 0x1ff;
pEntry->G_ID = 63;
/*(dec(A) + dec(B)*32) mod 512*/
} else if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_IBSS)) {
pEntry->P_AID = 0;
pEntry->G_ID = 63;
} else {
pEntry->P_AID = pSTA->RA[5];
/*BSSID[39:47]*/
pEntry->P_AID = (pEntry->P_AID << 1) | (pSTA->RA[4] >> 7);
pEntry->G_ID = 0;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: P_AID addressed to AP=0x%X\n", __func__, pEntry->P_AID));
}
cpMacAddr(pEntry->MacAddr, pSTA->RA);
pEntry->BeamformEntryCap = BeamformCap;
pEntry->PreLogSeq = 0; /*Modified by Jeffery @2015-04-13*/
pEntry->LogSeq = 0; /*Modified by Jeffery @2014-10-29*/
pEntry->LogRetryCnt = 0; /*Modified by Jeffery @2014-10-29*/
pEntry->LogSuccess = 0; /*LogSuccess is NOT needed to be accumulated, so LogSuccessCnt->LogSuccess, 2015-04-13, Jeffery*/
pEntry->ClockResetTimes = 0; /*Modified by Jeffery @2015-04-13*/
pEntry->NumofSoundingDim = NumofSoundingDim;
if (BeamformCap & BEAMFORMEE_CAP_VHT_MU) {
pDM_Odm->BeamformingInfo.beamformer_mu_cnt += 1;
pEntry->is_mu_ap = TRUE;
pEntry->AID = pSTA->AID;
} else if (BeamformCap & BEAMFORMEE_CAP_VHT_SU) {
pDM_Odm->BeamformingInfo.beamformer_su_cnt += 1;
pEntry->is_mu_ap = FALSE;
}
return pEntry;
}
else
return NULL;
}
#if 0
BOOLEAN
Beamforming_RemoveEntry(
IN PADAPTER Adapter,
IN pu1Byte RA,
OUT pu1Byte Idx
)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc;
PRT_BEAMFORMER_ENTRY pBFerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, RA, Idx);
PRT_BEAMFORMEE_ENTRY pEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, Idx);
BOOLEAN ret = FALSE;
RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s Start!\n", __func__));
RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s, pBFerEntry=0x%x\n", __func__, pBFerEntry));
RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s, pEntry=0x%x\n", __func__, pEntry));
if (pEntry != NULL) {
pEntry->bUsed = FALSE;
pEntry->BeamformEntryCap = BEAMFORMING_CAP_NONE;
/*pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;*/
pEntry->bBeamformingInProgress = FALSE;
ret = TRUE;
}
if (pBFerEntry != NULL) {
pBFerEntry->bUsed = FALSE;
pBFerEntry->BeamformEntryCap = BEAMFORMING_CAP_NONE;
ret = TRUE;
}
return ret;
}
#endif
/* Used for BeamformingStart_V1 */
VOID
phydm_Beamforming_NDPARate(
IN PVOID pDM_VOID,
CHANNEL_WIDTH BW,
u1Byte Rate
)
{
u2Byte NDPARate = Rate;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (NDPARate == 0) {
if(pDM_Odm->RSSI_Min > 30) // link RSSI > 30%
NDPARate = ODM_RATE24M;
else
NDPARate = ODM_RATE6M;
}
if (NDPARate < ODM_RATEMCS0)
BW = (CHANNEL_WIDTH)ODM_BW20M;
NDPARate = (NDPARate << 8) | BW;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_RATE, (pu1Byte)&NDPARate);
}
/* Used for BeamformingStart_SW and BeamformingStart_FW */
VOID
phydm_Beamforming_DymNDPARate(
IN PVOID pDM_VOID
)
{
u2Byte NDPARate = ODM_RATE6M, BW;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (pDM_Odm->RSSI_Min > 30) /*link RSSI > 30%*/
NDPARate = ODM_RATE24M;
else
NDPARate = ODM_RATE6M;
BW = ODM_BW20M;
NDPARate = NDPARate << 8 | BW;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_RATE, (pu1Byte)&NDPARate);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End, NDPA Rate = 0x%X\n", __func__, NDPARate));
}
/*
* SW Sounding : SW Timer unit 1ms
* HW Timer unit (1/32000) s 32k is clock.
* FW Sounding : FW Timer unit 10ms
*/
VOID
Beamforming_DymPeriod(
IN PVOID pDM_VOID,
IN u8 status
)
{
u1Byte Idx;
BOOLEAN bChangePeriod = FALSE;
u2Byte SoundPeriod_SW, SoundPeriod_FW;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMEE_ENTRY pBeamformEntry;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo);
PRT_BEAMFORMEE_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
//3 TODO per-client throughput caculation.
if ((*(pDM_Odm->pCurrentTxTP) + *(pDM_Odm->pCurrentRxTP) > 2) && ((pEntry->LogStatusFailCnt <= 20) || status)) {
SoundPeriod_SW = 40; /* 40ms */
SoundPeriod_FW = 40; /* From H2C cmd, unit = 10ms */
} else {
SoundPeriod_SW = 4000;/* 4s */
SoundPeriod_FW = 400;
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]SoundPeriod_SW=%d, SoundPeriod_FW=%d\n", __func__, SoundPeriod_SW, SoundPeriod_FW));
for (Idx = 0; Idx < BEAMFORMEE_ENTRY_NUM; Idx++) {
pBeamformEntry = pBeamInfo->BeamformeeEntry+Idx;
if (pBeamformEntry->DefaultCSICnt > 20) {
/*Modified by David*/
SoundPeriod_SW = 4000;
SoundPeriod_FW = 400;
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Period = %d\n", __func__, SoundPeriod_SW));
if (pBeamformEntry->BeamformEntryCap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) {
if (pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER) {
if (pBeamformEntry->SoundPeriod != SoundPeriod_FW) {
pBeamformEntry->SoundPeriod = SoundPeriod_FW;
bChangePeriod = TRUE; /*Only FW sounding need to send H2C packet to change sound period. */
}
} else if (pBeamformEntry->SoundPeriod != SoundPeriod_SW) {
pBeamformEntry->SoundPeriod = SoundPeriod_SW;
}
}
}
if (bChangePeriod)
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_FW_NDPA, (pu1Byte)&Idx);
}
BOOLEAN
Beamforming_SendHTNDPAPacket(
IN PVOID pDM_VOID,
IN pu1Byte RA,
IN CHANNEL_WIDTH BW,
IN u1Byte QIdx
)
{
BOOLEAN ret = TRUE;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
if (QIdx == BEACON_QUEUE)
ret = SendFWHTNDPAPacket(pDM_Odm, RA, BW);
else
ret = SendSWHTNDPAPacket(pDM_Odm, RA, BW);
return ret;
}
BOOLEAN
Beamforming_SendVHTNDPAPacket(
IN PVOID pDM_VOID,
IN pu1Byte RA,
IN u2Byte AID,
IN CHANNEL_WIDTH BW,
IN u1Byte QIdx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
BOOLEAN ret = TRUE;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
HalComTxbf_Set(pDM_Odm, TXBF_SET_GET_TX_RATE, NULL);
if ((pDM_Odm->TxBfDataRate >= ODM_RATEVHTSS3MCS7) && (pDM_Odm->TxBfDataRate <= ODM_RATEVHTSS3MCS9)) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("@%s: 3SS VHT 789 don't sounding\n", __func__));
} else {
if (QIdx == BEACON_QUEUE) /* Send to reserved page => FW NDPA */
ret = SendFWVHTNDPAPacket(pDM_Odm, RA, AID, BW);
else {
#ifdef SUPPORT_MU_BF
#if (SUPPORT_MU_BF == 1)
pBeamInfo->is_mu_sounding = TRUE;
ret = SendSWVHTMUNDPAPacket(pDM_Odm, BW);
#else
pBeamInfo->is_mu_sounding = FALSE;
ret = SendSWVHTNDPAPacket(pDM_Odm, RA, AID, BW);
#endif
#else
pBeamInfo->is_mu_sounding = FALSE;
ret = SendSWVHTNDPAPacket(pDM_Odm, RA, AID, BW);
#endif
}
}
return ret;
}
BEAMFORMING_NOTIFY_STATE
phydm_beamfomring_bSounding(
IN PVOID pDM_VOID,
PRT_BEAMFORMING_INFO pBeamInfo,
pu1Byte Idx
)
{
BEAMFORMING_NOTIFY_STATE bSounding = BEAMFORMING_NOTIFY_NONE;
RT_BEAMFORMING_OID_INFO BeamOidInfo = pBeamInfo->BeamformingOidInfo;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
/*if(( Beamforming_GetBeamCap(pBeamInfo) & BEAMFORMER_CAP) == 0)*/
/*bSounding = BEAMFORMING_NOTIFY_RESET;*/
if (BeamOidInfo.SoundOidMode == SOUNDING_STOP_All_TIMER)
bSounding = BEAMFORMING_NOTIFY_RESET;
else {
u1Byte i;
for (i = 0 ; i < BEAMFORMEE_ENTRY_NUM ; i++) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("@%s: BFee Entry %d bUsed=%d, bSound=%d\n", __func__, i, pBeamInfo->BeamformeeEntry[i].bUsed, pBeamInfo->BeamformeeEntry[i].bSound));
if (pBeamInfo->BeamformeeEntry[i].bUsed && (!pBeamInfo->BeamformeeEntry[i].bSound)) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: Add BFee entry %d\n", __func__, i));
*Idx = i;
if (pBeamInfo->BeamformeeEntry[i].is_mu_sta)
bSounding = BEAMFORMEE_NOTIFY_ADD_MU;
else
bSounding = BEAMFORMEE_NOTIFY_ADD_SU;
}
if ((!pBeamInfo->BeamformeeEntry[i].bUsed) && pBeamInfo->BeamformeeEntry[i].bSound) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: Delete BFee entry %d\n", __func__, i));
*Idx = i;
if (pBeamInfo->BeamformeeEntry[i].is_mu_sta)
bSounding = BEAMFORMEE_NOTIFY_DELETE_MU;
else
bSounding = BEAMFORMEE_NOTIFY_DELETE_SU;
}
}
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End, bSounding = %d\n", __func__, bSounding));
return bSounding;
}
//This function is unused
u1Byte
phydm_beamforming_SoundingIdx(
IN PVOID pDM_VOID,
PRT_BEAMFORMING_INFO pBeamInfo
)
{
u1Byte Idx = 0;
RT_BEAMFORMEE_ENTRY BeamEntry;
RT_BEAMFORMING_OID_INFO BeamOidInfo = pBeamInfo->BeamformingOidInfo;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (BeamOidInfo.SoundOidMode == SOUNDING_SW_HT_TIMER || BeamOidInfo.SoundOidMode == SOUNDING_SW_VHT_TIMER ||
BeamOidInfo.SoundOidMode == SOUNDING_HW_HT_TIMER || BeamOidInfo.SoundOidMode == SOUNDING_HW_VHT_TIMER)
Idx = BeamOidInfo.SoundOidIdx;
else {
u1Byte i;
for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
if (pBeamInfo->BeamformeeEntry[i].bUsed && (FALSE == pBeamInfo->BeamformeeEntry[i].bSound)) {
Idx = i;
break;
}
}
}
return Idx;
}
SOUNDING_MODE
phydm_beamforming_SoundingMode(
IN PVOID pDM_VOID,
PRT_BEAMFORMING_INFO pBeamInfo,
u1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte SupportInterface = pDM_Odm->SupportInterface;
RT_BEAMFORMEE_ENTRY BeamEntry = pBeamInfo->BeamformeeEntry[Idx];
RT_BEAMFORMING_OID_INFO BeamOidInfo = pBeamInfo->BeamformingOidInfo;
SOUNDING_MODE Mode = BeamOidInfo.SoundOidMode;
if (BeamOidInfo.SoundOidMode == SOUNDING_SW_VHT_TIMER || BeamOidInfo.SoundOidMode == SOUNDING_HW_VHT_TIMER) {
if (BeamEntry.BeamformEntryCap & BEAMFORMER_CAP_VHT_SU)
Mode = BeamOidInfo.SoundOidMode;
else
Mode = SOUNDING_STOP_All_TIMER;
} else if (BeamOidInfo.SoundOidMode == SOUNDING_SW_HT_TIMER || BeamOidInfo.SoundOidMode == SOUNDING_HW_HT_TIMER) {
if (BeamEntry.BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT)
Mode = BeamOidInfo.SoundOidMode;
else
Mode = SOUNDING_STOP_All_TIMER;
} else if (BeamEntry.BeamformEntryCap & BEAMFORMER_CAP_VHT_SU) {
if ((SupportInterface == ODM_ITRF_USB) && !(pDM_Odm->SupportICType & (ODM_RTL8814A | ODM_RTL8822B)))
Mode = SOUNDING_FW_VHT_TIMER;
else
Mode = SOUNDING_SW_VHT_TIMER;
} else if (BeamEntry.BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT) {
if ((SupportInterface == ODM_ITRF_USB) && !(pDM_Odm->SupportICType & (ODM_RTL8814A | ODM_RTL8822B)))
Mode = SOUNDING_FW_HT_TIMER;
else
Mode = SOUNDING_SW_HT_TIMER;
} else
Mode = SOUNDING_STOP_All_TIMER;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] SupportInterface=%d, Mode=%d\n", __func__, SupportInterface, Mode));
return Mode;
}
u2Byte
phydm_beamforming_SoundingTime(
IN PVOID pDM_VOID,
PRT_BEAMFORMING_INFO pBeamInfo,
SOUNDING_MODE Mode,
u1Byte Idx
)
{
u2Byte SoundingTime = 0xffff;
RT_BEAMFORMEE_ENTRY BeamEntry = pBeamInfo->BeamformeeEntry[Idx];
RT_BEAMFORMING_OID_INFO BeamOidInfo = pBeamInfo->BeamformingOidInfo;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (Mode == SOUNDING_HW_HT_TIMER || Mode == SOUNDING_HW_VHT_TIMER)
SoundingTime = BeamOidInfo.SoundOidPeriod * 32;
else if (Mode == SOUNDING_SW_HT_TIMER || Mode == SOUNDING_SW_VHT_TIMER)
/*Modified by David*/
SoundingTime = BeamEntry.SoundPeriod; /*BeamOidInfo.SoundOidPeriod;*/
else
SoundingTime = BeamEntry.SoundPeriod;
return SoundingTime;
}
CHANNEL_WIDTH
phydm_beamforming_SoundingBW(
IN PVOID pDM_VOID,
PRT_BEAMFORMING_INFO pBeamInfo,
SOUNDING_MODE Mode,
u1Byte Idx
)
{
CHANNEL_WIDTH SoundingBW = CHANNEL_WIDTH_20;
RT_BEAMFORMEE_ENTRY BeamEntry = pBeamInfo->BeamformeeEntry[Idx];
RT_BEAMFORMING_OID_INFO BeamOidInfo = pBeamInfo->BeamformingOidInfo;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
if (Mode == SOUNDING_HW_HT_TIMER || Mode == SOUNDING_HW_VHT_TIMER)
SoundingBW = BeamOidInfo.SoundOidBW;
else if (Mode == SOUNDING_SW_HT_TIMER || Mode == SOUNDING_SW_VHT_TIMER)
/*Modified by David*/
SoundingBW = BeamEntry.SoundBW; /*BeamOidInfo.SoundOidBW;*/
else
SoundingBW = BeamEntry.SoundBW;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s, SoundingBW=0x%X\n", __func__, SoundingBW));
return SoundingBW;
}
BOOLEAN
phydm_Beamforming_SelectBeamEntry(
IN PVOID pDM_VOID,
PRT_BEAMFORMING_INFO pBeamInfo
)
{
PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo);
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
/*pEntry.bSound is different between first and latter NDPA, and should not be used as BFee entry selection*/
/*BTW, latter modification should sync to the selection mechanism of AP/ADSL instead of the fixed SoundIdx.*/
pSoundInfo->SoundIdx = phydm_beamforming_SoundingIdx(pDM_Odm, pBeamInfo);
/*pSoundInfo->SoundIdx = 0;*/
if (pSoundInfo->SoundIdx < BEAMFORMEE_ENTRY_NUM)
pSoundInfo->SoundMode = phydm_beamforming_SoundingMode(pDM_Odm, pBeamInfo, pSoundInfo->SoundIdx);
else
pSoundInfo->SoundMode = SOUNDING_STOP_All_TIMER;
if (SOUNDING_STOP_All_TIMER == pSoundInfo->SoundMode) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Return because of SOUNDING_STOP_All_TIMER\n", __func__));
return FALSE;
} else {
pSoundInfo->SoundBW = phydm_beamforming_SoundingBW(pDM_Odm, pBeamInfo, pSoundInfo->SoundMode, pSoundInfo->SoundIdx );
pSoundInfo->SoundPeriod = phydm_beamforming_SoundingTime(pDM_Odm, pBeamInfo, pSoundInfo->SoundMode, pSoundInfo->SoundIdx );
return TRUE;
}
}
/*SU BFee Entry Only*/
BOOLEAN
phydm_beamforming_StartPeriod(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PADAPTER Adapter = pDM_Odm->Adapter;
BOOLEAN Ret = TRUE;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo);
phydm_Beamforming_DymNDPARate(pDM_Odm);
phydm_Beamforming_SelectBeamEntry(pDM_Odm, pBeamInfo); // Modified
if (pSoundInfo->SoundMode == SOUNDING_SW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_SW_HT_TIMER)
ODM_SetTimer(pDM_Odm, &pBeamInfo->BeamformingTimer, pSoundInfo->SoundPeriod);
else if (pSoundInfo->SoundMode == SOUNDING_HW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_HW_HT_TIMER ||
pSoundInfo->SoundMode == SOUNDING_AUTO_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_AUTO_HT_TIMER) {
HAL_HW_TIMER_TYPE TimerType = HAL_TIMER_TXBF;
u4Byte val = (pSoundInfo->SoundPeriod | (TimerType<<16));
//HW timer stop: All IC has the same setting
Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_HW_REG_TIMER_STOP, (pu1Byte)(&TimerType));
//ODM_Write1Byte(pDM_Odm, 0x15F, 0);
//HW timer init: All IC has the same setting, but 92E & 8812A only write 2 bytes
Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_HW_REG_TIMER_INIT, (pu1Byte)(&val));
//ODM_Write1Byte(pDM_Odm, 0x164, 1);
//ODM_Write4Byte(pDM_Odm, 0x15C, val);
//HW timer start: All IC has the same setting
Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_HW_REG_TIMER_START, (pu1Byte)(&TimerType));
//ODM_Write1Byte(pDM_Odm, 0x15F, 0x5);
} else if (pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER)
Ret = BeamformingStart_FW(pDM_Odm, pSoundInfo->SoundIdx);
else
Ret = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] SoundIdx=%d, SoundMode=%d, SoundBW=%d, SoundPeriod=%d\n", __func__,
pSoundInfo->SoundIdx, pSoundInfo->SoundMode, pSoundInfo->SoundBW, pSoundInfo->SoundPeriod));
return Ret;
}
// Used after Beamforming_Leave, and will clear the setting of the "already deleted" entry
/*SU BFee Entry Only*/
VOID
phydm_beamforming_EndPeriod_SW(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PADAPTER Adapter = pDM_Odm->Adapter;
u1Byte Idx = 0;
PRT_BEAMFORMEE_ENTRY pBeamformEntry;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo);
HAL_HW_TIMER_TYPE TimerType = HAL_TIMER_TXBF;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (pSoundInfo->SoundMode == SOUNDING_SW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_SW_HT_TIMER)
ODM_CancelTimer(pDM_Odm, &pBeamInfo->BeamformingTimer);
else if (pSoundInfo->SoundMode == SOUNDING_HW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_HW_HT_TIMER ||
pSoundInfo->SoundMode == SOUNDING_AUTO_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_AUTO_HT_TIMER)
/*HW timer stop: All IC has the same setting*/
Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_HW_REG_TIMER_STOP, (pu1Byte)(&TimerType));
/*ODM_Write1Byte(pDM_Odm, 0x15F, 0);*/
}
VOID
phydm_beamforming_EndPeriod_FW(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Idx = 0;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_FW_NDPA, (pu1Byte)&Idx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]\n", __func__));
}
/*SU BFee Entry Only*/
VOID
phydm_beamforming_ClearEntry_SW(
IN PVOID pDM_VOID,
BOOLEAN IsDelete,
u1Byte DeleteIdx
)
{
u1Byte Idx = 0;
PRT_BEAMFORMEE_ENTRY pBeamformEntry = NULL;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
if (IsDelete) {
if (DeleteIdx < BEAMFORMEE_ENTRY_NUM) {
pBeamformEntry = pBeamInfo->BeamformeeEntry + DeleteIdx;
if (!((!pBeamformEntry->bUsed) && pBeamformEntry->bSound)) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] SW DeleteIdx is wrong!!!!!\n", __func__));
return;
}
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] SW delete BFee entry %d\n", __func__, DeleteIdx));
if (pBeamformEntry->BeamformEntryState == BEAMFORMING_ENTRY_STATE_PROGRESSING) {
pBeamformEntry->bBeamformingInProgress = FALSE;
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
} else if (pBeamformEntry->BeamformEntryState == BEAMFORMING_ENTRY_STATE_PROGRESSED) {
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&DeleteIdx);
}
pBeamformEntry->bSound = FALSE;
} else {
for (Idx = 0; Idx < BEAMFORMEE_ENTRY_NUM; Idx++) {
pBeamformEntry = pBeamInfo->BeamformeeEntry+Idx;
/*Used after bSounding=RESET, and will clear the setting of "ever sounded" entry, which is not necessarily be deleted.*/
/*This function is mainly used in case "BeamOidInfo.SoundOidMode == SOUNDING_STOP_All_TIMER".*/
/*However, setting oid doesn't delete entries (bUsed is still TRUE), new entries may fail to be added in.*/
if (pBeamformEntry->bSound) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] SW reset BFee entry %d\n", __func__, Idx));
/*
* If End procedure is
* 1. Between (Send NDPA, C2H packet return), reset state to initialized.
* After C2H packet return , status bit will be set to zero.
*
* 2. After C2H packet, then reset state to initialized and clear status bit.
*/
if (pBeamformEntry->BeamformEntryState == BEAMFORMING_ENTRY_STATE_PROGRESSING)
phydm_Beamforming_End_SW(pDM_Odm, 0);
else if (pBeamformEntry->BeamformEntryState == BEAMFORMING_ENTRY_STATE_PROGRESSED) {
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&Idx);
}
pBeamformEntry->bSound = FALSE;
}
}
}
}
VOID
phydm_beamforming_ClearEntry_FW(
IN PVOID pDM_VOID,
BOOLEAN IsDelete,
u1Byte DeleteIdx
)
{
u1Byte Idx = 0;
PRT_BEAMFORMEE_ENTRY pBeamformEntry = NULL;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
if (IsDelete) {
if (DeleteIdx < BEAMFORMEE_ENTRY_NUM) {
pBeamformEntry = pBeamInfo->BeamformeeEntry + DeleteIdx;
if (!((!pBeamformEntry->bUsed) && pBeamformEntry->bSound)) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] FW DeleteIdx is wrong!!!!!\n", __func__));
return;
}
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: FW delete BFee entry %d\n", __func__, DeleteIdx));
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
pBeamformEntry->bSound = FALSE;
} else {
for (Idx = 0; Idx < BEAMFORMEE_ENTRY_NUM; Idx++) {
pBeamformEntry = pBeamInfo->BeamformeeEntry+Idx;
/*Used after bSounding=RESET, and will clear the setting of "ever sounded" entry, which is not necessarily be deleted.*/
/*This function is mainly used in case "BeamOidInfo.SoundOidMode == SOUNDING_STOP_All_TIMER".*/
/*However, setting oid doesn't delete entries (bUsed is still TRUE), new entries may fail to be added in.*/
if (pBeamformEntry->bSound) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]FW reset BFee entry %d\n", __func__, Idx));
/*
* If End procedure is
* 1. Between (Send NDPA, C2H packet return), reset state to initialized.
* After C2H packet return , status bit will be set to zero.
*
* 2. After C2H packet, then reset state to initialized and clear status bit.
*/
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED;
pBeamformEntry->bSound = FALSE;
}
}
}
}
/*
* Called :
* 1. Add and delete entry : Beamforming_Enter/Beamforming_Leave
* 2. FW trigger : Beamforming_SetTxBFen
* 3. Set OID_RT_BEAMFORMING_PERIOD : BeamformingControl_V2
*/
VOID
phydm_Beamforming_Notify(
IN PVOID pDM_VOID
)
{
u1Byte Idx=BEAMFORMEE_ENTRY_NUM;
BEAMFORMING_NOTIFY_STATE bSounding = BEAMFORMING_NOTIFY_NONE;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
bSounding = phydm_beamfomring_bSounding(pDM_Odm, pBeamInfo, &Idx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s, Before notify, bSounding=%d, Idx=%d\n", __func__, bSounding, Idx));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: pBeamInfo->beamformee_su_cnt = %d\n", __func__, pBeamInfo->beamformee_su_cnt));
switch (bSounding) {
case BEAMFORMEE_NOTIFY_ADD_SU:
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BEAMFORMEE_NOTIFY_ADD_SU\n", __func__));
phydm_beamforming_StartPeriod(pDM_Odm);
break;
case BEAMFORMEE_NOTIFY_DELETE_SU:
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BEAMFORMEE_NOTIFY_DELETE_SU\n", __func__));
if (pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER) {
phydm_beamforming_ClearEntry_FW(pDM_Odm, TRUE, Idx);
if (pBeamInfo->beamformee_su_cnt == 0) { /* For 2->1 entry, we should not cancel SW timer */
phydm_beamforming_EndPeriod_FW(pDM_Odm);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: No BFee left\n", __func__));
}
} else {
phydm_beamforming_ClearEntry_SW(pDM_Odm, TRUE, Idx);
if (pBeamInfo->beamformee_su_cnt == 0) { /* For 2->1 entry, we should not cancel SW timer */
phydm_beamforming_EndPeriod_SW(pDM_Odm);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: No BFee left\n", __func__));
}
}
break;
case BEAMFORMEE_NOTIFY_ADD_MU:
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BEAMFORMEE_NOTIFY_ADD_MU\n", __func__));
if (pBeamInfo->beamformee_mu_cnt == 2) {
/*if (pSoundInfo->SoundMode == SOUNDING_SW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_SW_HT_TIMER)
ODM_SetTimer(pDM_Odm, &pBeamInfo->BeamformingTimer, pSoundInfo->SoundPeriod);*/
ODM_SetTimer(pDM_Odm, &pBeamInfo->BeamformingTimer, 1000); /*Do MU sounding every 1sec*/
} else
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: Less or larger than 2 MU STAs, not to set timer\n", __func__));
break;
case BEAMFORMEE_NOTIFY_DELETE_MU:
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BEAMFORMEE_NOTIFY_DELETE_MU\n", __func__));
if (pBeamInfo->beamformee_mu_cnt == 1) {
/*if (pSoundInfo->SoundMode == SOUNDING_SW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_SW_HT_TIMER)*/{
ODM_CancelTimer(pDM_Odm, &pBeamInfo->BeamformingTimer);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: Less than 2 MU STAs, stop sounding\n", __func__));
}
}
break;
case BEAMFORMING_NOTIFY_RESET:
if (pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER) {
phydm_beamforming_ClearEntry_FW(pDM_Odm, FALSE, Idx);
phydm_beamforming_EndPeriod_FW(pDM_Odm);
} else {
phydm_beamforming_ClearEntry_SW(pDM_Odm, FALSE, Idx);
phydm_beamforming_EndPeriod_SW(pDM_Odm);
}
break;
default:
break;
}
}
BOOLEAN
Beamforming_InitEntry(
IN PVOID pDM_VOID,
IN u2Byte staIdx,
pu1Byte BFerBFeeIdx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMEE_ENTRY pBeamformEntry = NULL;
PRT_BEAMFORMER_ENTRY pBeamformerEntry = NULL;
PRT_BEAMFORM_STAINFO pSTA = NULL;
BEAMFORMING_CAP BeamformCap = BEAMFORMING_CAP_NONE;
u1Byte BFerIdx=0xF, BFeeIdx=0xF;
u1Byte NumofSoundingDim = 0, CompSteeringNumofBFer = 0;
pSTA = phydm_staInfoInit(pDM_Odm, staIdx);
/*The current setting does not support Beaforming*/
if (BEAMFORMING_CAP_NONE == pSTA->HtBeamformCap && BEAMFORMING_CAP_NONE == pSTA->VhtBeamformCap) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("The configuration disabled Beamforming! Skip...\n"));
return FALSE;
}
if (pSTA->WirelessMode < WIRELESS_MODE_N_24G)
return FALSE;
else { /*HT*/
/*We are Beamformee because the STA is Beamformer*/
if (TEST_FLAG(pSTA->CurBeamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
BeamformCap =(BEAMFORMING_CAP)(BeamformCap |BEAMFORMEE_CAP_HT_EXPLICIT);
NumofSoundingDim = (pSTA->CurBeamform&BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP)>>6;
}
/*We are Beamformer because the STA is Beamformee*/
if (TEST_FLAG(pSTA->CurBeamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE) ||
TEST_FLAG(pSTA->HtBeamformCap, BEAMFORMING_HT_BEAMFORMER_TEST)) {
BeamformCap =(BEAMFORMING_CAP)(BeamformCap | BEAMFORMER_CAP_HT_EXPLICIT);
CompSteeringNumofBFer = (pSTA->CurBeamform & BEAMFORMING_HT_BEAMFORMER_STEER_NUM)>>4;
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] HT CurBeamform=0x%X, BeamformCap=0x%X\n", __func__, pSTA->CurBeamform, BeamformCap));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] HT NumofSoundingDim=%d, CompSteeringNumofBFer=%d\n", __func__, NumofSoundingDim, CompSteeringNumofBFer));
#if (ODM_IC_11AC_SERIES_SUPPORT == 1)
if (pSTA->WirelessMode & WIRELESS_MODE_AC_5G || pSTA->WirelessMode & WIRELESS_MODE_AC_24G) { /*VHT*/
/* We are Beamformee because the STA is SU Beamformer*/
if (TEST_FLAG(pSTA->CurBeamformVHT, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {
BeamformCap =(BEAMFORMING_CAP)(BeamformCap |BEAMFORMEE_CAP_VHT_SU);
NumofSoundingDim = (pSTA->CurBeamformVHT & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM)>>12;
}
/* We are Beamformer because the STA is SU Beamformee*/
if (TEST_FLAG(pSTA->CurBeamformVHT, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) ||
TEST_FLAG(pSTA->VhtBeamformCap, BEAMFORMING_VHT_BEAMFORMER_TEST)) {
BeamformCap =(BEAMFORMING_CAP)(BeamformCap |BEAMFORMER_CAP_VHT_SU);
CompSteeringNumofBFer = (pSTA->CurBeamformVHT & BEAMFORMING_VHT_BEAMFORMER_STS_CAP)>>8;
}
/* We are Beamformee because the STA is MU Beamformer*/
if (TEST_FLAG(pSTA->CurBeamformVHT, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {
BeamformCap = (BEAMFORMING_CAP)(BeamformCap | BEAMFORMEE_CAP_VHT_MU);
NumofSoundingDim = (pSTA->CurBeamformVHT & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM)>>12;
}
/* We are Beamformer because the STA is MU Beamformee*/
if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP)) { /* Only AP mode supports to act an MU beamformer */
if (TEST_FLAG(pSTA->CurBeamformVHT, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE) ||
TEST_FLAG(pSTA->VhtBeamformCap, BEAMFORMING_VHT_BEAMFORMER_TEST)) {
BeamformCap = (BEAMFORMING_CAP)(BeamformCap | BEAMFORMER_CAP_VHT_MU);
CompSteeringNumofBFer = (pSTA->CurBeamformVHT & BEAMFORMING_VHT_BEAMFORMER_STS_CAP)>>8;
}
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]VHT CurBeamformVHT=0x%X, BeamformCap=0x%X\n", __func__, pSTA->CurBeamformVHT, BeamformCap));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]VHT NumofSoundingDim=0x%X, CompSteeringNumofBFer=0x%X\n", __func__, NumofSoundingDim, CompSteeringNumofBFer));
}
#endif
}
if(BeamformCap == BEAMFORMING_CAP_NONE)
return FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Self BF Entry Cap = 0x%02X\n", __func__, BeamformCap));
/*We are BFee, so the entry is BFer*/
if (BeamformCap & (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP_HT_EXPLICIT)) {
pBeamformerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, pSTA->RA, &BFerIdx);
if (pBeamformerEntry == NULL) {
pBeamformerEntry = Beamforming_AddBFerEntry(pDM_Odm, pSTA, BeamformCap, NumofSoundingDim , &BFerIdx);
if (pBeamformerEntry == NULL)
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]Not enough BFer entry!!!!!\n", __func__));
}
}
/*We are BFer, so the entry is BFee*/
if (BeamformCap & (BEAMFORMER_CAP_VHT_MU | BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP_HT_EXPLICIT)) {
pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, pSTA->RA, &BFeeIdx);
/*<2A>p<EFBFBD>GBFeeIdx = 0xF <20>h<EFBFBD>N<EFBFBD><4E><EFBFBD>ثeentry<72><79><EFBFBD><EFBFBD><EFBFBD>S<EFBFBD><53><EFBFBD>ۦP<DBA6><50>MACID<49>b<EFBFBD><62>*/
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Get BFee entry 0x%X by address\n", __func__, BFeeIdx));
if (pBeamformEntry == NULL) {
pBeamformEntry = Beamforming_AddBFeeEntry(pDM_Odm, pSTA, BeamformCap, NumofSoundingDim, CompSteeringNumofBFer, &BFeeIdx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]: pSTA->AID=%d, pSTA->MacID=%d\n", __func__, pSTA->AID, pSTA->MacID));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]: Add BFee entry %d\n", __func__, BFeeIdx));
if (pBeamformEntry == NULL)
return FALSE;
else
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
} else {
/*Entry has been created. If entry is initialing or progressing then errors occur.*/
if (pBeamformEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_INITIALIZED &&
pBeamformEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
return FALSE;
} else
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
}
pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED;
phydm_staInfoUpdate(pDM_Odm, staIdx, pBeamformEntry);
}
*BFerBFeeIdx = (BFerIdx<<4) | BFeeIdx;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] End: BFerIdx=0x%X, BFeeIdx=0x%X, BFerBFeeIdx=0x%X\n", __func__, BFerIdx, BFeeIdx, *BFerBFeeIdx));
return TRUE;
}
VOID
Beamforming_DeInitEntry(
IN PVOID pDM_VOID,
pu1Byte RA
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Idx = 0;
PRT_BEAMFORMER_ENTRY pBFerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, RA, &Idx);
PRT_BEAMFORMEE_ENTRY pBFeeEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
BOOLEAN ret = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (pBFeeEntry != NULL) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s, pBFeeEntry\n", __func__));
pBFeeEntry->bUsed = FALSE;
pBFeeEntry->BeamformEntryCap = BEAMFORMING_CAP_NONE;
pBFeeEntry->bBeamformingInProgress = FALSE;
if (pBFeeEntry->is_mu_sta) {
pDM_Odm->BeamformingInfo.beamformee_mu_cnt -= 1;
pDM_Odm->BeamformingInfo.FirstMUBFeeIndex = phydm_Beamforming_GetFirstMUBFeeEntryIdx(pDM_Odm);
} else {
pDM_Odm->BeamformingInfo.beamformee_su_cnt -= 1;
}
ret = TRUE;
}
if (pBFerEntry != NULL) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s, pBFerEntry\n", __func__));
pBFerEntry->bUsed = FALSE;
pBFerEntry->BeamformEntryCap = BEAMFORMING_CAP_NONE;
if (pBFerEntry->is_mu_ap)
pDM_Odm->BeamformingInfo.beamformer_mu_cnt -= 1;
else
pDM_Odm->BeamformingInfo.beamformer_su_cnt -= 1;
ret = TRUE;
}
if (ret == TRUE)
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_LEAVE, (pu1Byte)&Idx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End, Idx = 0x%X\n", __func__, Idx));
}
VOID
Beamforming_Reset(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Idx = 0;
PRT_BEAMFORMING_INFO pBeamformingInfo = &(pDM_Odm->BeamformingInfo);
for (Idx = 0; Idx < BEAMFORMEE_ENTRY_NUM; Idx++) {
if (pBeamformingInfo->BeamformeeEntry[Idx].bUsed == TRUE) {
pBeamformingInfo->BeamformeeEntry[Idx].bUsed = FALSE;
pBeamformingInfo->BeamformeeEntry[Idx].BeamformEntryCap = BEAMFORMING_CAP_NONE;
/*pBeamformingInfo->BeamformeeEntry[Idx].BeamformEntryState = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;*/
/*Modified by David*/
pBeamformingInfo->BeamformeeEntry[Idx].bBeamformingInProgress = FALSE;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_LEAVE, (pu1Byte)&Idx);
}
}
for (Idx = 0; Idx < BEAMFORMER_ENTRY_NUM; Idx++) {
pBeamformingInfo->BeamformerEntry[Idx].bUsed = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Idx=%d, bUsed=%d\n", __func__, Idx, pBeamformingInfo->BeamformerEntry[Idx].bUsed));
}
}
BOOLEAN
BeamformingStart_V1(
IN PVOID pDM_VOID,
pu1Byte RA,
BOOLEAN Mode,
CHANNEL_WIDTH BW,
u1Byte Rate
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Idx = 0;
PRT_BEAMFORMEE_ENTRY pEntry;
BOOLEAN ret = TRUE;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
pEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
if (pEntry->bUsed == FALSE) {
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
} else {
if (pEntry->bBeamformingInProgress)
return FALSE;
pEntry->bBeamformingInProgress = TRUE;
if (Mode == 1) {
if (!(pEntry->BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT)) {
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
}
} else if (Mode == 0) {
if (!(pEntry->BeamformEntryCap & BEAMFORMER_CAP_VHT_SU)) {
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
}
}
if (pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_INITIALIZED && pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
} else {
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_PROGRESSING;
pEntry->bSound = TRUE;
}
}
pEntry->SoundBW = BW;
pBeamInfo->BeamformeeCurIdx = Idx;
phydm_Beamforming_NDPARate(pDM_Odm, BW, Rate);
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&Idx);
if (Mode == 1)
ret = Beamforming_SendHTNDPAPacket(pDM_Odm, RA, BW, NORMAL_QUEUE);
else
ret = Beamforming_SendVHTNDPAPacket(pDM_Odm, RA, pEntry->AID, BW, NORMAL_QUEUE);
if (ret == FALSE) {
Beamforming_Leave(pDM_Odm, RA);
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
}
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Idx %d\n", __func__, Idx));
return TRUE;
}
BOOLEAN
BeamformingStart_SW(
IN PVOID pDM_VOID,
u1Byte Idx,
u1Byte Mode,
CHANNEL_WIDTH BW
)
{
pu1Byte RA = NULL;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMEE_ENTRY pEntry;
BOOLEAN ret = TRUE;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
pEntry = &(pBeamInfo->BeamformeeEntry[Idx]);
if (pEntry->bUsed == FALSE) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Skip Beamforming, no entry for Idx =%d\n", Idx));
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
} else {
if (pEntry->bBeamformingInProgress) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("bBeamformingInProgress, skip...\n"));
return FALSE;
}
pEntry->bBeamformingInProgress = TRUE;
RA = pEntry->MacAddr;
if (Mode == SOUNDING_SW_HT_TIMER || Mode == SOUNDING_HW_HT_TIMER || Mode == SOUNDING_AUTO_HT_TIMER) {
if (!(pEntry->BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT)) {
pEntry->bBeamformingInProgress = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Return by not support BEAMFORMER_CAP_HT_EXPLICIT <==\n", __func__));
return FALSE;
}
} else if (Mode == SOUNDING_SW_VHT_TIMER || Mode == SOUNDING_HW_VHT_TIMER || Mode == SOUNDING_AUTO_VHT_TIMER) {
if (!(pEntry->BeamformEntryCap & BEAMFORMER_CAP_VHT_SU)) {
pEntry->bBeamformingInProgress = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Return by not support BEAMFORMER_CAP_VHT_SU <==\n", __func__));
return FALSE;
}
}
if (pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_INITIALIZED && pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
pEntry->bBeamformingInProgress = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Return by incorrect BeamformEntryState(%d) <==\n", __func__, pEntry->BeamformEntryState));
return FALSE;
} else {
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_PROGRESSING;
pEntry->bSound = TRUE;
}
}
pBeamInfo->BeamformeeCurIdx = Idx;
/*2014.12.22 Luke: Need to be checked*/
/*GET_TXBF_INFO(Adapter)->fTxbfSet(Adapter, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&Idx);*/
if (Mode == SOUNDING_SW_HT_TIMER || Mode == SOUNDING_HW_HT_TIMER || Mode == SOUNDING_AUTO_HT_TIMER)
ret = Beamforming_SendHTNDPAPacket(pDM_Odm, RA , BW, NORMAL_QUEUE);
else
ret = Beamforming_SendVHTNDPAPacket(pDM_Odm, RA , pEntry->AID, BW, NORMAL_QUEUE);
if (ret == FALSE) {
Beamforming_Leave(pDM_Odm, RA);
pEntry->bBeamformingInProgress = FALSE;
return FALSE;
}
/*--------------------------
// Send BF Report Poll for MU BF
--------------------------*/
#ifdef SUPPORT_MU_BF
#if (SUPPORT_MU_BF == 1)
{
u1Byte idx, PollSTACnt = 0;
BOOLEAN bGetFirstBFee = FALSE;
if (pBeamInfo->beamformee_mu_cnt > 1) { /* More than 1 MU STA*/
for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
pEntry = &(pBeamInfo->BeamformeeEntry[idx]);
if (pEntry->is_mu_sta) {
if (bGetFirstBFee) {
PollSTACnt++;
if (PollSTACnt == (pBeamInfo->beamformee_mu_cnt - 1))/* The last STA*/
SendSWVHTBFReportPoll(pDM_Odm, pEntry->MacAddr, TRUE);
else
SendSWVHTBFReportPoll(pDM_Odm, pEntry->MacAddr, FALSE);
} else {
bGetFirstBFee = TRUE;
}
}
}
}
}
#endif
#endif
return TRUE;
}
BOOLEAN
BeamformingStart_FW(
IN PVOID pDM_VOID,
u1Byte Idx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
pu1Byte RA = NULL;
PRT_BEAMFORMEE_ENTRY pEntry;
BOOLEAN ret = TRUE;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
pEntry = &(pBeamInfo->BeamformeeEntry[Idx]);
if (pEntry->bUsed == FALSE) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Skip Beamforming, no entry for Idx =%d\n", Idx));
return FALSE;
}
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_PROGRESSING;
pEntry->bSound = TRUE;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_FW_NDPA, (pu1Byte)&Idx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] End, Idx=0x%X\n", __func__, Idx));
return TRUE;
}
VOID
Beamforming_CheckSoundingSuccess(
IN PVOID pDM_VOID,
BOOLEAN Status
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
PRT_BEAMFORMEE_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[David]@%s Start!\n", __func__));
if (Status == 1) {
if (pEntry->LogStatusFailCnt == 21)
Beamforming_DymPeriod(pDM_Odm, Status);
pEntry->LogStatusFailCnt = 0;
} else if (pEntry->LogStatusFailCnt <= 20) {
pEntry->LogStatusFailCnt++;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s LogStatusFailCnt %d\n", __func__, pEntry->LogStatusFailCnt));
}
if (pEntry->LogStatusFailCnt > 20) {
pEntry->LogStatusFailCnt = 21;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __func__));
Beamforming_DymPeriod(pDM_Odm, Status);
}
}
VOID
phydm_Beamforming_End_SW(
IN PVOID pDM_VOID,
BOOLEAN Status
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PRT_BEAMFORMEE_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]);
if (pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSING) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] BeamformStatus %d\n", __func__, pEntry->BeamformEntryState));
return;
}
if ((pDM_Odm->TxBfDataRate >= ODM_RATEVHTSS3MCS7) && (pDM_Odm->TxBfDataRate <= ODM_RATEVHTSS3MCS9)) {
ODM_RT_TRACE(pDM_Odm, BEAMFORMING_DEBUG, ODM_DBG_LOUD, ("[%s] VHT3SS 7,8,9, do not apply V matrix.\n", __func__));
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx));
} else if (Status == 1) {
pEntry->LogStatusFailCnt = 0;
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_PROGRESSED;
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx));
} else {
pEntry->LogStatusFailCnt++;
pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED;
HalComTxbf_Set(pDM_Odm, TXBF_SET_TX_PATH_RESET, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] LogStatusFailCnt %d\n", __func__, pEntry->LogStatusFailCnt));
}
if (pEntry->LogStatusFailCnt > 30) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s LogStatusFailCnt > 50, Stop SOUNDING\n", __func__));
pEntry->bSound = FALSE;
Beamforming_DeInitEntry(pDM_Odm, pEntry->MacAddr);
/*Modified by David - Every action of deleting entry should follow by Notify*/
phydm_Beamforming_Notify(pDM_Odm);
}
pEntry->bBeamformingInProgress = FALSE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: Status=%d\n", __func__, Status));
}
VOID
Beamforming_TimerCallback(
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
IN PVOID pDM_VOID
#elif(DM_ODM_SUPPORT_TYPE == ODM_CE)
IN PVOID pContext
#endif
)
{
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PADAPTER Adapter = pDM_Odm->Adapter;
#elif(DM_ODM_SUPPORT_TYPE == ODM_CE)
PADAPTER Adapter = (PADAPTER)pContext;
PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
PDM_ODM_T pDM_Odm = &pHalData->odmpriv;
#endif
BOOLEAN ret = FALSE;
PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo);
PRT_BEAMFORMEE_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]);
PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
if (pEntry->bBeamformingInProgress) {
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("bBeamformingInProgress, reset it\n"));
phydm_Beamforming_End_SW(pDM_Odm, 0);
}
ret = phydm_Beamforming_SelectBeamEntry(pDM_Odm, pBeamInfo);
#if (SUPPORT_MU_BF == 1)
if (ret && pBeamInfo->beamformee_mu_cnt > 1)
ret = 1;
else
ret = 0;
#endif
if (ret)
ret = BeamformingStart_SW(pDM_Odm, pSoundInfo->SoundIdx, pSoundInfo->SoundMode, pSoundInfo->SoundBW);
else
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s, Error value return from BeamformingStart_V2\n", __func__));
if ((pBeamInfo->beamformee_su_cnt != 0) || (pBeamInfo->beamformee_mu_cnt > 1)) {
if (pSoundInfo->SoundMode == SOUNDING_SW_VHT_TIMER || pSoundInfo->SoundMode == SOUNDING_SW_HT_TIMER)
ODM_SetTimer(pDM_Odm, &pBeamInfo->BeamformingTimer, pSoundInfo->SoundPeriod);
else {
u4Byte val = (pSoundInfo->SoundPeriod << 16) | HAL_TIMER_TXBF;
Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_HW_REG_TIMER_RESTART, (pu1Byte)(&val));
}
}
}
VOID
Beamforming_SWTimerCallback(
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
PRT_TIMER pTimer
#elif(DM_ODM_SUPPORT_TYPE == ODM_CE)
void *FunctionContext
#endif
)
{
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
PADAPTER Adapter = (PADAPTER)pTimer->Adapter;
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
Beamforming_TimerCallback(pDM_Odm);
#elif(DM_ODM_SUPPORT_TYPE == ODM_CE)
PDM_ODM_T pDM_Odm = (PDM_ODM_T)FunctionContext;
PADAPTER Adapter = pDM_Odm->Adapter;
if (Adapter->net_closed == TRUE)
return;
rtw_run_in_thread_cmd(Adapter, Beamforming_TimerCallback, Adapter);
#endif
}
VOID
phydm_Beamforming_Init(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PHAL_TXBF_INFO pTxbfInfo = &pBeamInfo->TxbfInfo;
PRT_BEAMFORMING_OID_INFO pBeamOidInfo = &(pBeamInfo->BeamformingOidInfo);
pBeamOidInfo->SoundOidMode = SOUNDING_STOP_OID_TIMER;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Mode (%d)\n", __func__, pBeamOidInfo->SoundOidMode));
pBeamInfo->beamformee_su_cnt = 0;
pBeamInfo->beamformer_su_cnt = 0;
pBeamInfo->beamformee_mu_cnt = 0;
pBeamInfo->beamformer_mu_cnt = 0;
pBeamInfo->beamformee_mu_reg_maping = 0;
pBeamInfo->mu_ap_index = 0;
pBeamInfo->is_mu_sounding = FALSE;
pBeamInfo->FirstMUBFeeIndex = 0xFF;
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
pBeamInfo->SourceAdapter = pDM_Odm->Adapter;
#endif
halComTxbf_beamformInit(pDM_Odm);
}
VOID
Beamforming_Enter(
IN PVOID pDM_VOID,
IN u2Byte staIdx
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte BFerBFeeIdx = 0xff;
if (Beamforming_InitEntry(pDM_Odm, staIdx, &BFerBFeeIdx))
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_ENTER, (pu1Byte)&BFerBFeeIdx);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] End!\n", __func__));
}
VOID
Beamforming_Leave(
IN PVOID pDM_VOID,
pu1Byte RA
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
if (RA == NULL)
Beamforming_Reset(pDM_Odm);
else
Beamforming_DeInitEntry(pDM_Odm, RA);
phydm_Beamforming_Notify(pDM_Odm);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] End!!\n", __func__));
}
#if 0
//Nobody calls this function
VOID
phydm_Beamforming_SetTxBFen(
IN PVOID pDM_VOID,
u1Byte MacId,
BOOLEAN bTxBF
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
u1Byte Idx = 0;
PRT_BEAMFORMEE_ENTRY pEntry;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
pEntry = phydm_Beamforming_GetEntryByMacId(pDM_Odm, MacId, &Idx);
if(pEntry == NULL)
return;
else
pEntry->bTxBF = bTxBF;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s MacId %d TxBF %d\n", __func__, pEntry->MacId, pEntry->bTxBF));
phydm_Beamforming_Notify(pDM_Odm);
}
#endif
BEAMFORMING_CAP
phydm_Beamforming_GetBeamCap(
IN PVOID pDM_VOID,
IN PRT_BEAMFORMING_INFO pBeamInfo
)
{
u1Byte i;
BOOLEAN bSelfBeamformer = FALSE;
BOOLEAN bSelfBeamformee = FALSE;
RT_BEAMFORMEE_ENTRY BeamformeeEntry;
RT_BEAMFORMER_ENTRY BeamformerEntry;
BEAMFORMING_CAP BeamformCap = BEAMFORMING_CAP_NONE;
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
BeamformeeEntry = pBeamInfo->BeamformeeEntry[i];
if (BeamformeeEntry.bUsed) {
bSelfBeamformer = TRUE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] BFee entry %d bUsed=TRUE\n", __func__, i));
break;
}
}
for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
BeamformerEntry = pBeamInfo->BeamformerEntry[i];
if (BeamformerEntry.bUsed) {
bSelfBeamformee = TRUE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s]: BFer entry %d bUsed=TRUE\n", __func__, i));
break;
}
}
if (bSelfBeamformer)
BeamformCap = (BEAMFORMING_CAP)(BeamformCap | BEAMFORMER_CAP);
if (bSelfBeamformee)
BeamformCap = (BEAMFORMING_CAP)(BeamformCap | BEAMFORMEE_CAP);
return BeamformCap;
}
BOOLEAN
BeamformingControl_V1(
IN PVOID pDM_VOID,
pu1Byte RA,
u1Byte AID,
u1Byte Mode,
CHANNEL_WIDTH BW,
u1Byte Rate
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
BOOLEAN ret = TRUE;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("AID (%d), Mode (%d), BW (%d)\n", AID, Mode, BW));
switch (Mode) {
case 0:
ret = BeamformingStart_V1(pDM_Odm, RA, 0, BW, Rate);
break;
case 1:
ret = BeamformingStart_V1(pDM_Odm, RA, 1, BW, Rate);
break;
case 2:
phydm_Beamforming_NDPARate(pDM_Odm, BW, Rate);
ret = Beamforming_SendVHTNDPAPacket(pDM_Odm, RA, AID, BW, NORMAL_QUEUE);
break;
case 3:
phydm_Beamforming_NDPARate(pDM_Odm, BW, Rate);
ret = Beamforming_SendHTNDPAPacket(pDM_Odm, RA, BW, NORMAL_QUEUE);
break;
}
return ret;
}
/*Only OID uses this function*/
BOOLEAN
phydm_BeamformingControl_V2(
IN PVOID pDM_VOID,
u1Byte Idx,
u1Byte Mode,
CHANNEL_WIDTH BW,
u2Byte Period
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
PRT_BEAMFORMING_OID_INFO pBeamOidInfo = &(pBeamInfo->BeamformingOidInfo);
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Idx (%d), Mode (%d), BW (%d), Period (%d)\n", Idx, Mode, BW, Period));
pBeamOidInfo->SoundOidIdx = Idx;
pBeamOidInfo->SoundOidMode = (SOUNDING_MODE) Mode;
pBeamOidInfo->SoundOidBW = BW;
pBeamOidInfo->SoundOidPeriod = Period;
phydm_Beamforming_Notify(pDM_Odm);
return TRUE;
}
VOID
phydm_Beamforming_Watchdog(
IN PVOID pDM_VOID
)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo;
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_TRACE, ("%s Start!\n", __func__));
if (pBeamInfo->beamformee_su_cnt == 0)
return;
Beamforming_DymPeriod(pDM_Odm,0);
phydm_Beamforming_DymNDPARate(pDM_Odm);
}
#endif