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