#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); /*如果BFeeIdx = 0xF 則代表目前entry當中沒有相同的MACID在內*/ 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