/* SPDX-License-Identifier: GPL-2.0 */ #include "mp_precomp.h" #include "phydm_precomp.h" #if WPP_SOFTWARE_TRACE #include "phydm_beamforming.tmh" #endif #if (BEAMFORMING_SUPPORT == 1) u1Byte Beamforming_GetHTNDPTxRate( IN PADAPTER Adapter, u1Byte CompSteeringNumofBFer ) { u1Byte Nr_index = 0; u1Byte NDPTxRate; /*Find Nr*/ if(IS_HARDWARE_TYPE_8814A(Adapter)) Nr_index = TxBF_Nr(halTxbf8814A_GetNtx(Adapter), 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 PADAPTER Adapter, u1Byte CompSteeringNumofBFer ) { u1Byte Nr_index = 0; u1Byte NDPTxRate; /*Find Nr*/ if(IS_HARDWARE_TYPE_8814A(Adapter)) Nr_index = TxBF_Nr(halTxbf8814A_GetNtx(Adapter), 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_BEAMFORMING_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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s ===>\n", __FUNCTION__)); 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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s ===>\n", __FUNCTION__)); 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_BEAMFORMING_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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s ===>\n", __FUNCTION__)); 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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s ===>\n", __FUNCTION__)); 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_BEAMFORMING_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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s ===>\n", __FUNCTION__)); 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", __FUNCTION__)); for(i = 0; i < BEAMFORMER_ENTRY_NUM; i++) { if(pBeamInfo->BeamformerEntry[i].bUsed == FALSE) { *Idx = i; return &(pBeamInfo->BeamformerEntry[i]); } } return NULL; } PRT_BEAMFORMING_ENTRY Beamforming_AddBFeeEntry( IN PADAPTER Adapter, IN pu1Byte RA, IN u2Byte AID, IN u2Byte MacID, IN CHANNEL_WIDTH BW, IN BEAMFORMING_CAP BeamformCap, IN u1Byte NumofSoundingDim, IN u1Byte CompSteeringNumofBFer, OUT pu1Byte Idx ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_ENTRY pEntry = phydm_Beamforming_GetFreeBFeeEntry(pDM_Odm, Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__)); if(pEntry != NULL) { pEntry->bUsed = TRUE; pEntry->AID = AID; pEntry->MacId = MacID; pEntry->SoundBW = BW; if(ACTING_AS_AP(Adapter)) { u2Byte BSSID = ((Adapter->CurrentAddress[5] & 0xf0) >> 4) ^ (Adapter->CurrentAddress[5] & 0xf); // BSSID[44:47] xor BSSID[40:43] pEntry->P_AID = (AID + BSSID * 32) & 0x1ff; // (dec(A) + dec(B)*32) mod 512 ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BFee P_AID addressed to STA=%d\n", __FUNCTION__,pEntry->P_AID)); } else if(ACTING_AS_IBSS(Adapter)) // Ad hoc mode { pEntry->P_AID = 0; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BFee P_AID as IBSS=%d\n", __FUNCTION__,pEntry->P_AID)); } else // client mode { pEntry->P_AID = RA[5]; // BSSID[39:47] pEntry->P_AID = (pEntry->P_AID << 1) | (RA[4] >> 7 ); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: BFee P_AID addressed to AP=0x%X\n", __FUNCTION__,pEntry->P_AID)); } cpMacAddr(pEntry->MacAddr, RA); pEntry->bTxBF = FALSE; pEntry->bSound = FALSE; //3 TODO SW/FW sound period 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; return pEntry; } else return NULL; } PRT_BEAMFORMER_ENTRY Beamforming_AddBFerEntry( IN PADAPTER Adapter, IN pu1Byte RA, IN u2Byte AID, IN BEAMFORMING_CAP BeamformCap, IN u1Byte NumofSoundingDim, OUT pu1Byte Idx ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMER_ENTRY pEntry = phydm_Beamforming_GetFreeBFerEntry(pDM_Odm, Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__)); if(pEntry != NULL) { pEntry->bUsed = TRUE; if(ACTING_AS_AP(Adapter)) { u2Byte BSSID = ((Adapter->CurrentAddress[5] & 0xf0) >> 4) ^ (Adapter->CurrentAddress[5] & 0xf); // BSSID[44:47] xor BSSID[40:43] pEntry->P_AID = (AID + BSSID * 32) & 0x1ff; // (dec(A) + dec(B)*32) mod 512 } else if(ACTING_AS_IBSS(Adapter)) { pEntry->P_AID = 0; } else { pEntry->P_AID = RA[5]; // BSSID[39:47] pEntry->P_AID = (pEntry->P_AID << 1) | (RA[4] >> 7 ); } cpMacAddr(pEntry->MacAddr, RA); pEntry->BeamformEntryCap = BeamformCap; pEntry->LogSeq = 0xff; // Modified by Jeffery @2014-10-29 pEntry->LogRetryCnt = 0; // Modified by Jeffery @2014-10-29 pEntry->LogSuccessCnt = 0; // Modified by Jeffery @2014-10-29 pEntry->NumofSoundingDim = NumofSoundingDim; return pEntry; } else return NULL; } 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_BEAMFORMING_ENTRY pEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, Idx); BOOLEAN ret = FALSE; RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s Start!\n", __FUNCTION__) ); RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s, pBFerEntry=0x%x \n", __FUNCTION__,pBFerEntry) ); RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s, pEntry=0x%x \n", __FUNCTION__,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; } /* 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", __FUNCTION__) ); 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->Adapter, 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", __FUNCTION__) ); 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->Adapter, TXBF_SET_SOUNDING_RATE, (pu1Byte)&NDPARate); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End, NDPA Rate = 0x%X \n", __FUNCTION__, 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; PADAPTER Adapter = pDM_Odm->Adapter; PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); PRT_BEAMFORMING_ENTRY pBeamformEntry; PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO((Adapter)); PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo); PRT_BEAMFORMING_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); //3 TODO per-client throughput caculation. if ((Adapter->TxStats.CurrentTxTP + Adapter->RxStats.CurrentRxTP > 2)&&((pEntry->LogStatusFailCnt <= 20) || status)){ //-@ Modified by David SoundPeriod_SW = 40; /* 32*20? */ SoundPeriod_FW = 40; /* From H2C cmd, unit = 10ms */ RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, current TRX TP>2, SoundPeriod_SW=%d, SoundPeriod_FW=%d\n", __FUNCTION__, SoundPeriod_SW, SoundPeriod_FW) ); } else{ //-@ Modified by David SoundPeriod_SW = 4000;/* 32*2000? */ SoundPeriod_FW = 400; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, current TRX TP<2, SoundPeriod_SW=%d, SoundPeriod_FW=%d\n", __FUNCTION__, 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; } RT_DISP(FBEAM, FBEAM_FUN, ("@%s Period = %d\n", __FUNCTION__, 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(Adapter, TXBF_SET_SOUNDING_FW_NDPA, (pu1Byte)&Idx); } VOID Beamforming_GidPAid( PADAPTER Adapter, PRT_TCB pTcb ) { u1Byte Idx = 0; u1Byte RA[6] ={0}; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); pu1Byte pHeader = GET_FRAME_OF_FIRST_FRAG(Adapter, pTcb); if(Adapter->HardwareType < HARDWARE_TYPE_RTL8192EE) return; else if(IS_WIRELESS_MODE_N(Adapter) == FALSE) return; GET_80211_HDR_ADDRESS1(pHeader, &RA); // VHT SU PPDU carrying one or more group addressed MPDUs or // Transmitting a VHT NDP intended for multiple recipients if( MacAddr_isBcst(RA) || MacAddr_isMulticast(RA) || pTcb->macId == MAC_ID_STATIC_FOR_BROADCAST_MULTICAST) { pTcb->G_ID = 63; pTcb->P_AID = 0; } else if(ACTING_AS_AP(Adapter)) { u2Byte AID = (u2Byte) (MacIdGetOwnerAssociatedClientAID(Adapter, pTcb->macId) & 0x1ff); //AID[0:8] pTcb->G_ID = 63; if(AID == 0) //A PPDU sent by an AP to a non associated STA pTcb->P_AID = 0; else { //Sent by an AP and addressed to a STA associated with that AP u2Byte BSSID = 0; GET_80211_HDR_ADDRESS2(pHeader, &RA); BSSID = ((RA[5] & 0xf0) >> 4) ^ (RA[5] & 0xf); // BSSID[44:47] xor BSSID[40:43] pTcb->P_AID = (AID + BSSID * 32) & 0x1ff; // (dec(A) + dec(B)*32) mod 512 } } else if(ACTING_AS_IBSS(Adapter)) { pTcb->G_ID = 63; // P_AID for infrasturcture mode; MACID for ad-hoc mode. pTcb->P_AID = pTcb->macId; } else if(MgntLinkStatusQuery(Adapter)) { // Addressed to AP pTcb->G_ID = 0; GET_80211_HDR_ADDRESS1(pHeader, &RA); pTcb->P_AID = RA[5]; // RA[39:47] pTcb->P_AID = (pTcb->P_AID << 1) | (RA[4] >> 7 ); } else { pTcb->G_ID = 63; pTcb->P_AID = 0; } //RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X \n", __FUNCTION__, pTcb->G_ID, pTcb->P_AID) ); } RT_STATUS Beamforming_GetReportFrame( IN PADAPTER Adapter, IN PRT_RFD pRfd, IN POCTET_STRING pPduOS ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMING_ENTRY pBeamformEntry = NULL; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); pu1Byte pMIMOCtrlField, pCSIReport, pCSIMatrix; u1Byte Idx, Nc, Nr, CH_W; u2Byte CSIMatrixLen = 0; ACT_PKT_TYPE pktType = ACT_PKT_TYPE_UNKNOWN; //Memory comparison to see if CSI report is the same with previous one pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, Frame_Addr2(*pPduOS), &Idx); if( pBeamformEntry == NULL ) { RT_DISP(FBEAM, FBEAM_DATA, ("Beamforming_GetReportFrame: Cannot find entry by addr\n")); return RT_STATUS_FAILURE; } pktType = PacketGetActionFrameType(pPduOS); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); //-@ Modified by David if(pktType == ACT_PKT_VHT_COMPRESSED_BEAMFORMING) { pMIMOCtrlField = pPduOS->Octet + 26; Nc = ((*pMIMOCtrlField) & 0x7) + 1; Nr = (((*pMIMOCtrlField) & 0x38) >> 3) + 1; CH_W = (((*pMIMOCtrlField) & 0xC0) >> 6); pCSIMatrix = pMIMOCtrlField + 3 + Nc; //24+(1+1+3)+2 MAC header+(Category+ActionCode+MIMOControlField) +SNR(Nc=2) CSIMatrixLen = pPduOS->Length - 26 -3 -Nc; } else if(pktType == ACT_PKT_HT_COMPRESSED_BEAMFORMING) { pMIMOCtrlField = pPduOS->Octet + 26; Nc = ((*pMIMOCtrlField) & 0x3) + 1; Nr = (((*pMIMOCtrlField) & 0xC) >> 2) + 1; CH_W = (((*pMIMOCtrlField) & 0x10) >> 4); pCSIMatrix = pMIMOCtrlField + 6 + Nr; //24+(1+1+6)+2 MAC header+(Category+ActionCode+MIMOControlField) +SNR(Nc=2) CSIMatrixLen = pPduOS->Length - 26 -6 -Nr; } else return RT_STATUS_SUCCESS; if(pktType == ACT_PKT_VHT_COMPRESSED_BEAMFORMING) { RT_DISP(FBEAM, FBEAM_FUN, ("[David]@BF_GetReportFrame: idx=%d, pkt type=VHT_Cprssed_BF, Nc=%d, Nr=%d, CH_W=%d\n", Idx, Nc, Nr, CH_W)); } else if(pktType == ACT_PKT_HT_COMPRESSED_BEAMFORMING) { RT_DISP(FBEAM, FBEAM_FUN, ("[David]@BF_GetReportFrame: idx=%d, pkt type=HT_Cprssed_BF, Nc=%d, Nr=%d, CH_W=%d\n", Idx, Nc, Nr, CH_W)); } // RT_DISP_DATA(FBEAM, FBEAM_DATA, "Beamforming_GetReportFrame \n", pMIMOCtrlField, pPduOS->Length - 26); //-@ Modified by David - CSI buffer is not big enough, and comparison would result in blue screen /* if(pBeamformEntry->CSIMatrixLen != CSIMatrixLen) pBeamformEntry->DefaultCSICnt = 0; else if(PlatformCompareMemory(pBeamformEntry->CSIMatrix, pCSIMatrix, CSIMatrixLen)) { pBeamformEntry->DefaultCSICnt = 0; RT_DISP(FBEAM, FBEAM_FUN, ("%s CSI report is NOT the same with previos one\n", __FUNCTION__)); } else if(pBeamformEntry->DefaultCSICnt <= 20) { pBeamformEntry->DefaultCSICnt ++; RT_DISP(FBEAM, FBEAM_FUN, ("%s CSI report is the SAME with previos one\n", __FUNCTION__)); } pBeamformEntry->CSIMatrixLen = CSIMatrixLen; PlatformMoveMemory(&pBeamformEntry->CSIMatrix, pCSIMatrix, CSIMatrixLen); */ return RT_STATUS_SUCCESS; } VOID Beamforming_GetNDPAFrame( IN PADAPTER Adapter, IN OCTET_STRING pduOS ) { pu1Byte TA ; u1Byte Idx, Sequence; pu1Byte pNDPAFrame = pduOS.Octet; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); // PRT_BEAMFORMING_ENTRY pBeamformEntry = NULL; PRT_BEAMFORMER_ENTRY pBeamformerEntry = NULL; // Modified By Jeffery @2014-10-29 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); RT_DISP_DATA(FBEAM, FBEAM_DATA, "Beamforming_GetNDPAFrame\n", pduOS.Octet, pduOS.Length); if(IsCtrlNDPA(pNDPAFrame) == FALSE){ RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s IsCtrlNDPA(pNDPAFrame) == FALSE\n", __FUNCTION__) ); return; } else if( (IS_HARDWARE_TYPE_8812(Adapter) == FALSE)&&(IS_HARDWARE_TYPE_8821(Adapter) == FALSE) ) { RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s IsCtrlNDPA(pNDPAFrame) == FALSE\n", __FUNCTION__) ); return; } TA = Frame_Addr2(pduOS); // Remove signaling TA. TA[0] = TA[0] & 0xFE; // pBeamformEntry = Beamforming_GetBFeeEntryByAddr(Adapter, TA, &Idx); pBeamformerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, TA, &Idx); // Modified By Jeffery @2014-10-29 RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s After phydm_Beamforming_GetBFerEntryByAddr,pBeamformerEntry=0x%x\n", __FUNCTION__,pBeamformerEntry) ); if(pBeamformerEntry == NULL) return; else if(!(pBeamformerEntry->BeamformEntryCap & BEAMFORMEE_CAP_VHT_SU)) return; // else if(pBeamformerEntry->LogSuccessCnt > 1) //¼È®É²¾°£,Á×§K¥Ã»·¥d¦º¦b³o­Óª¬ºA // return; /* RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s begin, LogSeq=%d, LogRetryCnt=%d, LogSuccessCnt=%d\n", __FUNCTION__, pBeamformerEntry->LogSeq, pBeamformerEntry->LogRetryCnt, pBeamformerEntry->LogSuccessCnt) ); */ Sequence = (pNDPAFrame[16]) >> 2; if(pBeamformerEntry->LogSeq != Sequence){ /* Previous frame doesn't retry when meet new sequence number */ if(pBeamformerEntry->LogSeq != 0xff && pBeamformerEntry->LogRetryCnt == 0) pBeamformerEntry->LogSuccessCnt++; pBeamformerEntry->LogSeq = Sequence; pBeamformerEntry->PreLogSeq = pBeamformerEntry->LogSeq; /* break option for clcok reset, 2015-03-30, Jeffery */ if ((pBeamformerEntry->LogSeq != Sequence) && (pBeamformerEntry->PreLogSeq != pBeamformerEntry->LogSeq)) pBeamformerEntry->LogRetryCnt = 0; } else { /* pBeamformerEntry->LogSeq == Sequence */ pBeamformerEntry->PreLogSeq = pBeamformerEntry->LogSeq; if (pBeamformerEntry->LogRetryCnt == 3){ RT_DISP(FBEAM, FBEAM_FUN, ("[Jeffery]@%s begin, Clock Reset!!!,PreLogSeq=%d, LogSeq=%d, LogRetryCnt=%d, LogSuccessCnt=%d\n", __FUNCTION__, pBeamformerEntry->PreLogSeq, pBeamformerEntry->LogSeq, pBeamformerEntry->LogRetryCnt)); pBeamformerEntry->LogRetryCnt = 0; HalComTxbf_Set(Adapter, TXBF_SET_SOUNDING_CLK, NULL); } else pBeamformerEntry->LogRetryCnt++; } /* else { if(pBeamformerEntry->LogRetryCnt == 3) HalComTxbf_Set(Adapter, TXBF_SET_SOUNDING_CLK, NULL); else if(pBeamformerEntry->LogRetryCnt <= 3) pBeamformerEntry->LogRetryCnt++; } */ /* RT_DISP(FBEAM, FBEAM_FUN, ("%s End, LogSeq=%d, LogRetryCnt=%d, LogSuccessCnt=%d\n", __FUNCTION__, pBeamformerEntry->LogSeq, pBeamformerEntry->LogRetryCnt, pBeamformerEntry->LogSuccessCnt));*/ } VOID ConstructHTNDPAPacket( PADAPTER Adapter, pu1Byte RA, pu1Byte Buffer, pu4Byte pLength, CHANNEL_WIDTH BW ) { u2Byte Duration= 0; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo); OCTET_STRING pNDPAFrame,ActionContent; u1Byte ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; PlatformZeroMemory(Buffer, 32); SET_80211_HDR_FRAME_CONTROL(Buffer,0); SET_80211_HDR_ORDER(Buffer, 1); SET_80211_HDR_TYPE_AND_SUBTYPE(Buffer,Type_Action_No_Ack); SET_80211_HDR_ADDRESS1(Buffer, RA); SET_80211_HDR_ADDRESS2(Buffer, Adapter->CurrentAddress); SET_80211_HDR_ADDRESS3(Buffer, pMgntInfo->Bssid); Duration = 2*aSifsTime + 40; if(BW== CHANNEL_WIDTH_40) Duration+= 87; else Duration+= 180; SET_80211_HDR_DURATION(Buffer, Duration); //HT control field SET_HT_CTRL_CSI_STEERING(Buffer+sMacHdrLng, 3); SET_HT_CTRL_NDP_ANNOUNCEMENT(Buffer+sMacHdrLng, 1); FillOctetString(pNDPAFrame, Buffer, sMacHdrLng+sHTCLng); FillOctetString(ActionContent, ActionHdr, 4); PacketAppendData(&pNDPAFrame, ActionContent); *pLength = 32; } BOOLEAN SendFWHTNDPAPacket( IN PADAPTER Adapter, IN pu1Byte RA, IN CHANNEL_WIDTH BW ) { PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u4Byte BufLen; pu1Byte BufAddr; u1Byte DescLen = 0, Idx = 0, NDPTxRate; PADAPTER pDefAdapter = GetDefaultAdapter(Adapter); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMING_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); if(pBeamformEntry == NULL) return FALSE; NDPTxRate = Beamforming_GetHTNDPTxRate(Adapter, pBeamformEntry->CompSteeringNumofBFer); RT_DISP(FBEAM, FBEAM_FUN, ("%s, NDPTxRate =%d\n", __FUNCTION__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if(MgntGetFWBuffer(pDefAdapter, &pTcb, &pBuf)) { #if(DEV_BUS_TYPE != RT_PCI_INTERFACE) HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); DescLen = Adapter->HWDescHeadLength - pHalData->USBALLDummyLength; #endif BufAddr = pBuf->Buffer.VirtualAddress + DescLen; ConstructHTNDPAPacket( Adapter, RA, BufAddr, &BufLen, BW ); pTcb->PacketLength = BufLen + DescLen; pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; if(ACTING_AS_IBSS(Adapter) || ACTING_AS_AP(Adapter)) pTcb->G_ID = 63; pTcb->P_AID = pBeamformEntry->P_AID; pTcb->DataRate = NDPTxRate; /*rate of NDP decide by Nr*/ Adapter->HalFunc.CmdSendPacketHandler(Adapter, pTcb, pBuf, pTcb->PacketLength, DESC_PACKET_TYPE_NORMAL, FALSE); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if(ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } BOOLEAN SendSWHTNDPAPacket( IN PADAPTER Adapter, IN pu1Byte RA, IN CHANNEL_WIDTH BW ) { PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte Idx = 0, NDPTxRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMING_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); NDPTxRate = Beamforming_GetHTNDPTxRate(Adapter, pBeamformEntry->CompSteeringNumofBFer); RT_DISP(FBEAM, FBEAM_FUN, ("%s, NDPTxRate =%d\n", __FUNCTION__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if(MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructHTNDPAPacket( Adapter, RA, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength, BW ); pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if(ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } BOOLEAN Beamforming_SendHTNDPAPacket( IN PADAPTER Adapter, IN pu1Byte RA, IN CHANNEL_WIDTH BW, IN u1Byte QIdx ) { BOOLEAN ret = TRUE; if(QIdx == BEACON_QUEUE) ret = SendFWHTNDPAPacket(Adapter, RA, BW); else ret = SendSWHTNDPAPacket(Adapter, RA, BW); return ret; } VOID ConstructVHTNDPAPacket( PADAPTER Adapter, pu1Byte RA, u2Byte AID, pu1Byte Buffer, pu4Byte pLength, CHANNEL_WIDTH BW ) { u2Byte Duration= 0; u1Byte Sequence = 0; pu1Byte pNDPAFrame = Buffer; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo); RT_NDPA_STA_INFO STAInfo; // Frame control. SET_80211_HDR_FRAME_CONTROL(pNDPAFrame, 0); SET_80211_HDR_TYPE_AND_SUBTYPE(pNDPAFrame, Type_NDPA); SET_80211_HDR_ADDRESS1(pNDPAFrame, RA); SET_80211_HDR_ADDRESS2(pNDPAFrame, Adapter->CurrentAddress); Duration = 2*aSifsTime + 44; if(BW == CHANNEL_WIDTH_80) Duration += 40; else if(BW == CHANNEL_WIDTH_40) Duration+= 87; else Duration+= 180; SET_80211_HDR_DURATION(pNDPAFrame, Duration); Sequence = pMgntInfo->SoundingSequence << 2; PlatformMoveMemory(pNDPAFrame+16, &Sequence,1); if( ACTING_AS_IBSS(Adapter) || (ACTING_AS_AP(Adapter) == FALSE)) AID = 0; STAInfo.AID = AID; STAInfo.FeedbackType = 0; STAInfo.NcIndex = 0; PlatformMoveMemory(pNDPAFrame+17, (pu1Byte)&STAInfo, 2); *pLength = 19; } BOOLEAN SendFWVHTNDPAPacket( IN PADAPTER Adapter, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW ) { PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u4Byte BufLen; pu1Byte BufAddr; u1Byte DescLen = 0, Idx = 0, NDPTxRate = 0; PADAPTER pDefAdapter = GetDefaultAdapter(Adapter); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMING_ENTRY pBeamformEntry =phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); if(pBeamformEntry == NULL) return FALSE; NDPTxRate = Beamforming_GetVHTNDPTxRate(Adapter, pBeamformEntry->CompSteeringNumofBFer); RT_DISP(FBEAM, FBEAM_FUN, ("%s, NDPTxRate =%d\n", __FUNCTION__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if(MgntGetFWBuffer(pDefAdapter, &pTcb, &pBuf)) { #if(DEV_BUS_TYPE != RT_PCI_INTERFACE) HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); DescLen = Adapter->HWDescHeadLength - pHalData->USBALLDummyLength; #endif BufAddr = pBuf->Buffer.VirtualAddress + DescLen; ConstructVHTNDPAPacket( Adapter, RA, AID, BufAddr, &BufLen, BW ); pTcb->PacketLength = BufLen + DescLen; pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; if(ACTING_AS_IBSS(Adapter) || ACTING_AS_AP(Adapter)) pTcb->G_ID = 63; pTcb->P_AID = pBeamformEntry->P_AID; pTcb->DataRate = NDPTxRate; /*decide by Nr*/ Adapter->HalFunc.CmdSendPacketHandler(Adapter, pTcb, pBuf, pTcb->PacketLength, DESC_PACKET_TYPE_NORMAL, FALSE); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); RT_DISP(FBEAM, FBEAM_FUN, ("@%s End, ret=%d \n", __FUNCTION__,ret)); if(ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } BOOLEAN SendSWVHTNDPAPacket( IN PADAPTER Adapter, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW ) { PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte Idx = 0, NDPTxRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMING_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); NDPTxRate = Beamforming_GetVHTNDPTxRate(Adapter, pBeamformEntry->CompSteeringNumofBFer); RT_DISP(FBEAM, FBEAM_FUN, ("%s, NDPTxRate =%d\n", __FUNCTION__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if(MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructVHTNDPAPacket( Adapter, RA, AID, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength, BW ); pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; /*rate of NDP decide by Nr*/ MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); RT_DISP(FBEAM, FBEAM_FUN, ("%s\n", __FUNCTION__)); if(ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } BOOLEAN Beamforming_SendVHTNDPAPacket( IN PADAPTER Adapter, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW, IN u1Byte QIdx ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; BOOLEAN ret = TRUE; HalComTxbf_Set(Adapter, 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) ret = SendFWVHTNDPAPacket(Adapter, RA, AID, BW); else ret = SendSWVHTNDPAPacket(Adapter, RA, AID, BW); } 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", __FUNCTION__) ); // 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;iBeamformeeEntry[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", __FUNCTION__, i)); *Idx = i; bSounding = BEAMFORMING_NOTIFY_ADD; } 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", __FUNCTION__, i)); *Idx = i; bSounding = BEAMFORMING_NOTIFY_DELETE; } } } ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End, bSounding = %d\n", __FUNCTION__, bSounding) ); return bSounding; } //This function is unused u1Byte phydm_beamforming_SoundingIdx( IN PVOID pDM_VOID, PRT_BEAMFORMING_INFO pBeamInfo ) { u1Byte Idx = 0; RT_BEAMFORMING_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", __FUNCTION__) ); 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_BEAMFORMING_ENTRY BeamEntry = pBeamInfo->BeamformeeEntry[Idx]; RT_BEAMFORMING_OID_INFO BeamOidInfo = pBeamInfo->BeamformingOidInfo; SOUNDING_MODE Mode = BeamOidInfo.SoundOidMode; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); // RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s: OID mode is %d\n", __FUNCTION__, 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)) 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)) Mode = SOUNDING_FW_HT_TIMER; else Mode = SOUNDING_SW_HT_TIMER; } else Mode = SOUNDING_STOP_All_TIMER; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, SupportInterface=%d, Mode=%d \n", __FUNCTION__, 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_BEAMFORMING_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", __FUNCTION__) ); 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; //100*32; //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_BEAMFORMING_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", __FUNCTION__) ); 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", __FUNCTION__, 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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); // 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) 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; } } 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); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); 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(Adapter, 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", __FUNCTION__, pSoundInfo->SoundIdx, pSoundInfo->SoundMode, pSoundInfo->SoundBW, pSoundInfo->SoundPeriod)); return Ret; } // Used after Beamforming_Leave, and will clear the setting of the "already deleted" entry 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_BEAMFORMING_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", __FUNCTION__) ); 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; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); phydm_Beamforming_End_FW(pDM_Odm); } VOID phydm_beamforming_ClearEntry_SW( IN PVOID pDM_VOID, BOOLEAN IsDelete, u1Byte DeleteIdx ) { u1Byte Idx = 0; PRT_BEAMFORMING_ENTRY pBeamformEntry = NULL; 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_LOUD, ("%s Start!\n", __FUNCTION__) ); if(IsDelete) { if(DeleteIdxBeamformeeEntry + DeleteIdx; if(!((!pBeamformEntry->bUsed) && pBeamformEntry->bSound)) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: SW DeleteIdx is wrong!!!!! \n",__FUNCTION__)); return; } } ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: SW delete BFee entry %d \n", __FUNCTION__, 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->Adapter, 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", __FUNCTION__, 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->Adapter, 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_BEAMFORMING_ENTRY pBeamformEntry = NULL; 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_LOUD, ("%s Start!\n", __FUNCTION__) ); if(IsDelete) { if(DeleteIdxBeamformeeEntry + DeleteIdx; if(!((!pBeamformEntry->bUsed) && pBeamformEntry->bSound)) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: FW DeleteIdx is wrong!!!!! \n",__FUNCTION__)); return; } } ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s: FW delete BFee entry %d \n", __FUNCTION__, 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", __FUNCTION__, 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, ("[Beamforming]%s Start!\n", __FUNCTION__) ); bSounding = phydm_beamfomring_bSounding(pDM_Odm, pBeamInfo, &Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[Beamforming]%s, Before notify, BeamformState=%d, bSounding=%d, Idx=%d\n", __FUNCTION__, pBeamInfo->BeamformState, bSounding, Idx)); if(pBeamInfo->BeamformState == BEAMFORMING_STATE_END) { if(bSounding==BEAMFORMING_NOTIFY_ADD) { if(phydm_beamforming_StartPeriod(pDM_Odm) == TRUE) pBeamInfo->BeamformState = BEAMFORMING_STATE_START_1BFee; } } else if(pBeamInfo->BeamformState == BEAMFORMING_STATE_START_1BFee) { if(bSounding==BEAMFORMING_NOTIFY_ADD) { if(phydm_beamforming_StartPeriod(pDM_Odm) == TRUE) pBeamInfo->BeamformState = BEAMFORMING_STATE_START_2BFee; else pBeamInfo->BeamformState = BEAMFORMING_STATE_START_1BFee; } else if(bSounding==BEAMFORMING_NOTIFY_DELETE) { if(pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER) { phydm_beamforming_ClearEntry_FW(pDM_Odm, TRUE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_FW(pDM_Odm); } else { phydm_beamforming_ClearEntry_SW(pDM_Odm, TRUE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_SW(pDM_Odm); } pBeamInfo->BeamformState = BEAMFORMING_STATE_END; } else if(bSounding==BEAMFORMING_NOTIFY_RESET) { if(pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER) { phydm_beamforming_ClearEntry_FW(pDM_Odm, FALSE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_FW(pDM_Odm); } else { phydm_beamforming_ClearEntry_SW(pDM_Odm, FALSE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_SW(pDM_Odm); } pBeamInfo->BeamformState = BEAMFORMING_STATE_END; } } else if(pBeamInfo->BeamformState == BEAMFORMING_STATE_START_2BFee) { if(bSounding==BEAMFORMING_NOTIFY_ADD) { RT_ASSERT(FALSE, ("[David]@%s: Should be blocked at InitEntry!!!!! \n", __FUNCTION__)); } else if(bSounding==BEAMFORMING_NOTIFY_DELETE) { if(pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER) { phydm_beamforming_ClearEntry_FW(pDM_Odm, TRUE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_FW(pDM_Odm); } else { // For 2->1 entry, we should not cancel SW timer phydm_beamforming_ClearEntry_SW(pDM_Odm, TRUE, Idx); } pBeamInfo->BeamformState = BEAMFORMING_STATE_START_1BFee; } else if(bSounding==BEAMFORMING_NOTIFY_RESET) { if(pSoundInfo->SoundMode == SOUNDING_FW_HT_TIMER || pSoundInfo->SoundMode == SOUNDING_FW_VHT_TIMER) { phydm_beamforming_ClearEntry_FW(pDM_Odm, FALSE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_FW(pDM_Odm); } else { phydm_beamforming_ClearEntry_SW(pDM_Odm, FALSE, Idx); // Modified by Jeffery @ 2014-11-04 phydm_beamforming_EndPeriod_SW(pDM_Odm); } pBeamInfo->BeamformState = BEAMFORMING_STATE_END; } } else RT_ASSERT(FALSE, ("%s BeamformState %d\n", __FUNCTION__, pBeamInfo->BeamformState)); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End, after Notify, BeamformState =%d\n", __FUNCTION__, pBeamInfo->BeamformState)); } BOOLEAN Beamforming_InitEntry( PADAPTER Adapter, PRT_WLAN_STA pSTA, pu1Byte BFerBFeeIdx ) { PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo); PRT_VERY_HIGH_THROUGHPUT pVHTInfo = GET_VHT_INFO(pMgntInfo); PRT_BEAMFORMING_ENTRY pBeamformEntry = NULL; PRT_BEAMFORMER_ENTRY pBeamformerEntry = NULL; pu1Byte RA; u2Byte AID, MacID; WIRELESS_MODE WirelessMode; CHANNEL_WIDTH BW = CHANNEL_WIDTH_20; BEAMFORMING_CAP BeamformCap = BEAMFORMING_CAP_NONE; u1Byte BFerIdx=0xF, BFeeIdx=0xF; u1Byte NumofSoundingDim = 0, CompSteeringNumofBFer = 0; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__)); // The current setting does not support Beaforming if(BEAMFORMING_CAP_NONE == pHTInfo->HtBeamformCap && BEAMFORMING_CAP_NONE == pVHTInfo->VhtBeamformCap) { RT_DISP(FBEAM, FBEAM_ERROR, ("The configuration disabled Beamforming! Skip...\n")); return FALSE; } // IBSS, AP mode if(pSTA != NULL) { AID = pSTA->AID; RA = pSTA->MacAddr; MacID = pSTA->AssociatedMacId; WirelessMode = pSTA->WirelessMode; BW = pSTA->BandWidth; } else // Client mode { AID = pMgntInfo->mAId; RA = pMgntInfo->Bssid; MacID = pMgntInfo->mMacId; WirelessMode = pMgntInfo->dot11CurrentWirelessMode; BW = pMgntInfo->dot11CurrentChannelBandWidth; } if(WirelessMode < WIRELESS_MODE_N_24G) return FALSE; else { //3 // HT u1Byte CurBeamform; u2Byte CurBeamformVHT; if(pSTA != NULL) CurBeamform = pSTA->HTInfo.HtCurBeamform; else CurBeamform = pHTInfo->HtCurBeamform; // We are Beamformee because the STA is Beamformer if(TEST_FLAG(CurBeamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { BeamformCap =(BEAMFORMING_CAP)(BeamformCap |BEAMFORMEE_CAP_HT_EXPLICIT); NumofSoundingDim = (CurBeamform&BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP)>>6; } // We are Beamformer because the STA is Beamformee if( TEST_FLAG(CurBeamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE) || TEST_FLAG(pHTInfo->HtBeamformCap, BEAMFORMING_HT_BEAMFORMER_TEST)) { BeamformCap =(BEAMFORMING_CAP)(BeamformCap | BEAMFORMER_CAP_HT_EXPLICIT); CompSteeringNumofBFer = (CurBeamform & BEAMFORMING_HT_BEAMFORMER_STEER_NUM)>>4; } RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, CurBeamform=0x%X, BeamformCap=0x%X\n", __FUNCTION__, CurBeamform, BeamformCap)); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, NumofSoundingDim=%d, CompSteeringNumofBFer=%d\n", __FUNCTION__, NumofSoundingDim, CompSteeringNumofBFer)); if(WirelessMode == WIRELESS_MODE_AC_5G || WirelessMode == WIRELESS_MODE_AC_24G) { //3 // VHT if(pSTA != NULL) CurBeamformVHT = pSTA->VHTInfo.VhtCurBeamform; else CurBeamformVHT = pVHTInfo->VhtCurBeamform; // We are Beamformee because the STA is Beamformer if(TEST_FLAG(CurBeamformVHT, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) { BeamformCap =(BEAMFORMING_CAP)(BeamformCap |BEAMFORMEE_CAP_VHT_SU); NumofSoundingDim = (CurBeamformVHT & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM)>>12; } // We are Beamformer because the STA is Beamformee if( TEST_FLAG(CurBeamformVHT, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) || TEST_FLAG(pVHTInfo->VhtBeamformCap, BEAMFORMING_VHT_BEAMFORMER_TEST)) { BeamformCap =(BEAMFORMING_CAP)(BeamformCap |BEAMFORMER_CAP_VHT_SU); CompSteeringNumofBFer = (CurBeamformVHT & BEAMFORMING_VHT_BEAMFORMER_STS_CAP)>>8; } RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, CurBeamformVHT=0x%X, BeamformCap=0x%X\n", __FUNCTION__, CurBeamformVHT, BeamformCap)); RT_DISP(FBEAM, FBEAM_FUN, ("%s, NumofSoundingDim=0x%X, CompSteeringNumofBFer=0x%X\n", __FUNCTION__, NumofSoundingDim, CompSteeringNumofBFer)); } } if(BeamformCap == BEAMFORMING_CAP_NONE) return FALSE; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, Self BF Entry Cap = 0x%02X\n", __FUNCTION__, BeamformCap)); // We are BFee, so the entry is BFer if((BeamformCap & BEAMFORMEE_CAP_VHT_SU) || (BeamformCap & BEAMFORMEE_CAP_HT_EXPLICIT)) { pBeamformerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, RA, &BFerIdx); if(pBeamformerEntry == NULL) { pBeamformerEntry = Beamforming_AddBFerEntry(Adapter, RA, AID, BeamformCap, NumofSoundingDim ,&BFerIdx); if(pBeamformerEntry == NULL) RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s: Not enough BFer entry!!!!! \n", __FUNCTION__)); } } // We are BFer, so the entry is BFee if((BeamformCap & BEAMFORMER_CAP_VHT_SU) || (BeamformCap & BEAMFORMER_CAP_HT_EXPLICIT)) { pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &BFeeIdx); // ¦pªGBFeeIdx = 0xF «h¥Nªí¥Ø«eentry·í¤¤¨S¦³¬Û¦PªºMACID¦b¤º RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s: Get BFee entry 0x%X by address \n", __FUNCTION__, BFeeIdx)); if(pBeamformEntry == NULL) { pBeamformEntry = Beamforming_AddBFeeEntry(Adapter, RA, AID, MacID, BW, BeamformCap, NumofSoundingDim, CompSteeringNumofBFer, &BFeeIdx); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s: Add BFee entry %d \n", __FUNCTION__, 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) { RT_ASSERT(TRUE, ("Error State of Beamforming")); return FALSE; } else pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZEING; } pBeamformEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED; } *BFerBFeeIdx = (BFerIdx<<4) | BFeeIdx; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End: BFerIdx=0x%X, BFeeIdx=0x%X, BFerBFeeIdx=0x%X \n", __FUNCTION__, BFerIdx, BFeeIdx, *BFerBFeeIdx)); return TRUE; } VOID Beamforming_DeInitEntry( PADAPTER Adapter, pu1Byte RA ) { u1Byte Idx = 0; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s Start!\n", __FUNCTION__) ); if(Beamforming_RemoveEntry(Adapter, RA, &Idx) == TRUE) { HalComTxbf_Set(Adapter, TXBF_SET_SOUNDING_LEAVE, (pu1Byte)&Idx); } RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, Idx = 0x%X\n", __FUNCTION__, Idx)); } VOID Beamforming_Reset( PADAPTER Adapter ) { u1Byte Idx = 0; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_INFO pBeamformingInfo = GET_BEAMFORM_INFO(Adapter); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); 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(Adapter, TXBF_SET_SOUNDING_LEAVE, (pu1Byte)&Idx); } } for(Idx = 0; Idx < BEAMFORMER_ENTRY_NUM; Idx++) { pBeamformingInfo->BeamformerEntry[Idx].bUsed = FALSE; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s, Idx=%d, bUsed=%d \n", __FUNCTION__, Idx, pBeamformingInfo->BeamformerEntry[Idx].bUsed)); } } BOOLEAN BeamformingStart_V1( PADAPTER Adapter, pu1Byte RA, BOOLEAN Mode, CHANNEL_WIDTH BW, u1Byte Rate ) { u1Byte Idx = 0; PRT_BEAMFORMING_ENTRY pEntry; BOOLEAN ret = TRUE; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); pEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); if(pEntry->bUsed == FALSE) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, no entry for addr = "), RA); pEntry->bBeamformingInProgress = FALSE; return FALSE; } else { if(pEntry->bBeamformingInProgress) { RT_DISP(FBEAM, FBEAM_ERROR, ("bBeamformingInProgress, skip...\n")); return FALSE; } pEntry->bBeamformingInProgress = TRUE; if(Mode == 1) { if(!(pEntry->BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT)) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, entry without BEAMFORMEE_CAP_HT_EXPLICIT for addr = "), RA); pEntry->bBeamformingInProgress = FALSE; return FALSE; } } else if(Mode == 0) { if(!(pEntry->BeamformEntryCap & BEAMFORMER_CAP_VHT_SU)) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, entry without BEAMFORMEE_CAP_VHT_SU for addr = "), RA); pEntry->bBeamformingInProgress = FALSE; return FALSE; } } if( pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_INITIALIZED && pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSED) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, state without (BEAMFORMING_STATE_INITIALIZED | BEAMFORMING_STATE_PROGRESSED) for addr = "), RA); 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(Adapter, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&Idx); if(Mode == 1) ret = Beamforming_SendHTNDPAPacket(Adapter,RA, BW, NORMAL_QUEUE); else ret = Beamforming_SendVHTNDPAPacket(Adapter,RA, pEntry->AID, BW, NORMAL_QUEUE); if(ret == FALSE) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Beamforming_RemoveEntry because of failure sending NDPA for addr = "), RA); /* Beamforming_RemoveEntry(Adapter, RA, &Idx);*/ RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s calls Beamforming_Leave, RA=0x%x \n", __FUNCTION__,RA) ); Beamforming_Leave(Adapter, RA); pEntry->bBeamformingInProgress = FALSE; return FALSE; } RT_DISP(FBEAM, FBEAM_FUN, ("%s Idx %d\n", __FUNCTION__, Idx)); return TRUE; } BOOLEAN BeamformingStart_SW( PADAPTER Adapter, u1Byte Idx, u1Byte Mode, CHANNEL_WIDTH BW ) { pu1Byte RA = NULL; PRT_BEAMFORMING_ENTRY pEntry; BOOLEAN ret = TRUE; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); pEntry = &(pBeamInfo->BeamformeeEntry[Idx]); if(pEntry->bUsed == FALSE) { RT_DISP(FBEAM, FBEAM_ERROR, ("Skip Beamforming, no entry for Idx =%d\n", Idx)); pEntry->bBeamformingInProgress = FALSE; return FALSE; } else { if(pEntry->bBeamformingInProgress) { RT_DISP(FBEAM, FBEAM_ERROR, ("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)) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, entry without BEAMFORMEE_CAP_HT_EXPLICIT for addr = "), RA); pEntry->bBeamformingInProgress = FALSE; 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)) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, entry without BEAMFORMEE_CAP_VHT_SU for addr = "), RA); pEntry->bBeamformingInProgress = FALSE; return FALSE; } } if( pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_INITIALIZED && pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSED) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Skip Beamforming, state without (BEAMFORMING_STATE_INITIALIZED | BEAMFORMING_STATE_PROGRESSED) for addr = "), RA); pEntry->bBeamformingInProgress = FALSE; 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(Adapter,RA, BW, NORMAL_QUEUE); else ret = Beamforming_SendVHTNDPAPacket(Adapter,RA, pEntry->AID, BW, NORMAL_QUEUE); if(ret == FALSE) { RT_DISP_ADDR(FBEAM, FBEAM_ERROR, ("Beamforming_RemoveEntry because of failure sending NDPA for addr = "), RA); RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s calls Beamforming_Leave, RA=0x%x \n", __FUNCTION__,RA) ); Beamforming_Leave(Adapter, RA); pEntry->bBeamformingInProgress = FALSE; return FALSE; } if(Mode == SOUNDING_SW_HT_TIMER || Mode == SOUNDING_HW_HT_TIMER || Mode == SOUNDING_AUTO_HT_TIMER) { RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s: Send HT NDPA for current idx=%d\n", __FUNCTION__, Idx)); } else { RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s: Send VHT NDPA for current idx=%d\n", __FUNCTION__, Idx)); } return TRUE; } BOOLEAN BeamformingStart_FW( PADAPTER Adapter, u1Byte Idx ) { pu1Byte RA = NULL; PRT_BEAMFORMING_ENTRY pEntry; BOOLEAN ret = TRUE; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); pEntry = &(pBeamInfo->BeamformeeEntry[Idx]); if(pEntry->bUsed == FALSE) { RT_DISP(FBEAM, FBEAM_ERROR, ("Skip Beamforming, no entry for Idx =%d\n", Idx)); return FALSE; } pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_PROGRESSING; pEntry->bSound = TRUE; HalComTxbf_Set(Adapter, TXBF_SET_SOUNDING_FW_NDPA, (pu1Byte)&Idx); RT_DISP(FBEAM, FBEAM_FUN, ("@%s End, Idx=0x%X \n", __FUNCTION__, Idx)); return TRUE; } VOID Beamforming_CheckSoundingSuccess( PADAPTER Adapter, BOOLEAN Status ) { PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); PRT_BEAMFORMING_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); if(Status == 1){ if(pEntry->LogStatusFailCnt == 21) Beamforming_DymPeriod(pDM_Odm,Status); pEntry->LogStatusFailCnt = 0; } else if(pEntry->LogStatusFailCnt <= 20){ pEntry->LogStatusFailCnt++; RT_DISP(FBEAM, FBEAM_ERROR, ("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt)); } if(pEntry->LogStatusFailCnt > 20){ pEntry->LogStatusFailCnt = 21; RT_DISP(FBEAM, FBEAM_ERROR, ("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __FUNCTION__)); 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_BEAMFORMING_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); if(pEntry->BeamformEntryState != BEAMFORMING_ENTRY_STATE_PROGRESSING) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s BeamformStatus %d\n", __FUNCTION__, 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->Adapter, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx)); } else if (Status == 1) { pEntry->LogStatusFailCnt = 0; pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_PROGRESSED; HalComTxbf_Set(pDM_Odm->Adapter, TXBF_SET_SOUNDING_STATUS, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx)); } else { pEntry->LogStatusFailCnt++; pEntry->BeamformEntryState = BEAMFORMING_ENTRY_STATE_INITIALIZED; HalComTxbf_Set(pDM_Odm->Adapter, TXBF_SET_TX_PATH_RESET, (pu1Byte)&(pBeamInfo->BeamformeeCurIdx)); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt)); } if(pEntry->LogStatusFailCnt > 50) { RT_DISP(FBEAM, FBEAM_ERROR, ("%s LogStatusFailCnt > 50, Stop SOUNDING\n", __FUNCTION__)); pEntry->bSound = FALSE; Beamforming_DeInitEntry(pDM_Odm->Adapter, 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", __FUNCTION__, Status)); } VOID phydm_Beamforming_End_FW( IN PVOID pDM_VOID ) { u1Byte Idx = 0; PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start! \n", __FUNCTION__) ); HalComTxbf_Set(Adapter, TXBF_SET_SOUNDING_FW_NDPA, (pu1Byte)&Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s End! \n", __FUNCTION__)); } VOID Beamforming_TimerCallback( PADAPTER Adapter ) { BOOLEAN ret = FALSE; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); PRT_BEAMFORMING_INFO pBeamInfo = GET_BEAMFORM_INFO(Adapter); PRT_BEAMFORMING_ENTRY pEntry = &(pBeamInfo->BeamformeeEntry[pBeamInfo->BeamformeeCurIdx]); PRT_SOUNDING_INFO pSoundInfo = &(pBeamInfo->SoundingInfo); 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", __FUNCTION__) ); 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(ret) ret = BeamformingStart_SW(Adapter,pSoundInfo->SoundIdx, pSoundInfo->SoundMode, pSoundInfo->SoundBW); if(ret) ; else { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s, Error value return from BeamformingStart_V2 \n", __FUNCTION__)); } if(pBeamInfo->BeamformState >= BEAMFORMING_STATE_START_1BFee) { 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( PRT_TIMER pTimer ) { PADAPTER Adapter=(PADAPTER)pTimer->Adapter; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start!\n", __FUNCTION__) ); Beamforming_TimerCallback(Adapter); } 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); RT_DISP(FBEAM, FBEAM_FUN, ("%s Start!\n", __FUNCTION__) ); pBeamOidInfo->SoundOidMode = SOUNDING_STOP_OID_TIMER; RT_DISP(FBEAM, FBEAM_FUN, ("%s Mode (%d)\n", __FUNCTION__, pBeamOidInfo->SoundOidMode)); } VOID Beamforming_Enter( PADAPTER Adapter, PRT_WLAN_STA pSTA ) { u1Byte BFerBFeeIdx = 0xff; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s Start! \n", __FUNCTION__) ); if(Beamforming_InitEntry(Adapter, pSTA, &BFerBFeeIdx)) HalComTxbf_Set(Adapter, TXBF_SET_SOUNDING_ENTER, (pu1Byte)&BFerBFeeIdx); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End! \n", __FUNCTION__) ); } VOID Beamforming_Leave( PADAPTER Adapter, pu1Byte RA ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s Start! \n", __FUNCTION__) ); if(RA == NULL) Beamforming_Reset(Adapter); else Beamforming_DeInitEntry(Adapter, RA); phydm_Beamforming_Notify(pDM_Odm); RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End!! \n", __FUNCTION__)); } //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_BEAMFORMING_ENTRY pEntry; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); 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", __FUNCTION__, pEntry->MacId, pEntry->bTxBF)); phydm_Beamforming_Notify(pDM_Odm); } BEAMFORMING_CAP phydm_Beamforming_GetBeamCap( IN PVOID pDM_VOID, IN PRT_BEAMFORMING_INFO pBeamInfo ) { u1Byte i; BOOLEAN bSelfBeamformer = FALSE; BOOLEAN bSelfBeamformee = FALSE; RT_BEAMFORMING_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, ("[Beamforming]%s Start!\n", __FUNCTION__) ); /* for(i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) { BeamformEntry = pBeamInfo->BeamformeeEntry[i]; if(BeamformEntry.bUsed) { if( (BeamformEntry.BeamformEntryCap & BEAMFORMEE_CAP_VHT_SU) || (BeamformEntry.BeamformEntryCap & BEAMFORMEE_CAP_HT_EXPLICIT)) bSelfBeamformee = TRUE; if( (BeamformEntry.BeamformEntryCap & BEAMFORMER_CAP_VHT_SU) || (BeamformEntry.BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT)) bSelfBeamformer = TRUE; } if(bSelfBeamformer && bSelfBeamformee) i = BEAMFORMEE_ENTRY_NUM; } */ 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, ("[Beamforming]%s: BFee entry %d bUsed=TRUE \n", __FUNCTION__, 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, ("[Beamforming]%s: BFer entry %d bUsed=TRUE \n", __FUNCTION__, i)); break; } } if(bSelfBeamformer) BeamformCap = (BEAMFORMING_CAP)(BeamformCap | BEAMFORMER_CAP); if(bSelfBeamformee) BeamformCap = (BEAMFORMING_CAP)(BeamformCap | BEAMFORMEE_CAP); return BeamformCap; } BOOLEAN BeamformingControl_V1( PADAPTER Adapter, pu1Byte RA, u1Byte AID, u1Byte Mode, CHANNEL_WIDTH BW, u1Byte Rate ) { BOOLEAN ret = TRUE; 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", __FUNCTION__) ); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("AID (%d), Mode (%d), BW (%d)\n", AID, Mode, BW)); RT_DISP_ADDR(FBEAM, FBEAM_FUN, ("Addr = "), RA); switch(Mode){ case 0: ret = BeamformingStart_V1(Adapter, RA, 0, BW, Rate); break; case 1: ret = BeamformingStart_V1(Adapter, RA, 1, BW, Rate); break; case 2: phydm_Beamforming_NDPARate(pDM_Odm, BW, Rate); ret = Beamforming_SendVHTNDPAPacket(Adapter,RA, AID, BW, NORMAL_QUEUE); break; case 3: phydm_Beamforming_NDPARate(pDM_Odm, BW, Rate); ret = Beamforming_SendHTNDPAPacket(Adapter, 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", __FUNCTION__) ); 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; PADAPTER Adapter = pDM_Odm->Adapter; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("%s Start!\n", __FUNCTION__) ); if(pBeamInfo->BeamformState < BEAMFORMING_STATE_START_1BFee) return; Beamforming_DymPeriod(pDM_Odm,0); phydm_Beamforming_DymNDPARate(pDM_Odm); } #endif