1960 lines
61 KiB
C
1960 lines
61 KiB
C
#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)) {
|
||
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s => sta_info(mac_id:%d) failed\n", __func__, staIdx));
|
||
rtw_warn_on(1);
|
||
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|BEAMFORMER_CAP_HT_EXPLICIT)) {
|
||
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|BEAMFORMEE_CAP_HT_EXPLICIT)) {
|
||
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) && (pBeamInfo->snding3SS == FALSE)) {
|
||
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_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;
|
||
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 {
|
||
if (pSTA->WirelessMode & WIRELESS_MODE_N_5G || pSTA->WirelessMode & WIRELESS_MODE_N_24G) {/*HT*/
|
||
if (TEST_FLAG(pSTA->CurBeamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {/*We are Beamformee because the STA is Beamformer*/
|
||
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));
|
||
}
|
||
|
||
|
||
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);
|
||
|
||
if (pBeamInfo->is_mu_sounding) {
|
||
pBeamInfo->is_mu_sounding_in_progress = TRUE;
|
||
pEntry = &(pBeamInfo->BeamformeeEntry[Idx]);
|
||
RA = pEntry->MacAddr;
|
||
|
||
} else {
|
||
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;
|
||
PRT_BEAMFORMEE_ENTRY pEntry;
|
||
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 (pBeamInfo->is_mu_sounding) {
|
||
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: MU sounding done\n", __func__));
|
||
pBeamInfo->is_mu_sounding_in_progress = FALSE;
|
||
HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx));
|
||
} else {
|
||
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) && (pBeamInfo->snding3SS == FALSE)) {
|
||
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, 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 > 50) {
|
||
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);
|
||
BOOLEAN bBeamformingInProgress;
|
||
|
||
ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __func__));
|
||
|
||
if (pBeamInfo->is_mu_sounding)
|
||
bBeamformingInProgress = pBeamInfo->is_mu_sounding_in_progress;
|
||
else
|
||
bBeamformingInProgress = pEntry->bBeamformingInProgress;
|
||
|
||
if (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;
|
||
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;
|
||
pBeamInfo->applyVmatrix = TRUE;
|
||
pBeamInfo->snding3SS = FALSE;
|
||
|
||
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
|
||
pBeamInfo->SourceAdapter = pDM_Odm->Adapter;
|
||
#endif
|
||
halComTxbf_beamformInit(pDM_Odm);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
phydm_actingDetermine(
|
||
IN PVOID pDM_VOID,
|
||
IN PHYDM_ACTING_TYPE type
|
||
)
|
||
{
|
||
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
|
||
BOOLEAN ret = FALSE;
|
||
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
|
||
PADAPTER Adapter = pDM_Odm->BeamformingInfo.SourceAdapter;
|
||
#else
|
||
PADAPTER Adapter = pDM_Odm->Adapter;
|
||
#endif
|
||
|
||
#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)
|
||
if (type == PhyDM_ACTING_AS_AP)
|
||
ret = ACTING_AS_AP(Adapter);
|
||
else if (type == PhyDM_ACTING_AS_IBSS)
|
||
ret = ACTING_AS_IBSS(Adapter);
|
||
#elif (DM_ODM_SUPPORT_TYPE & ODM_CE)
|
||
struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
|
||
|
||
if (type == PhyDM_ACTING_AS_AP)
|
||
ret = check_fwstate(pmlmepriv, WIFI_AP_STATE);
|
||
else if (type == PhyDM_ACTING_AS_IBSS)
|
||
ret = check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
|
||
#endif
|
||
|
||
return ret;
|
||
|
||
}
|
||
|
||
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_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
|