net: wireless: rockchip_wlan: add rtl8188eu support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8188eu / hal / phydm / txbf / haltxbfinterface.c
1 //============================================================
2 // Description:
3 //
4 // This file is for TXBF interface mechanism
5 //
6 //============================================================
7 #include "mp_precomp.h"
8 #include "../phydm_precomp.h"
9
10 #if (BEAMFORMING_SUPPORT == 1)
11 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
12 VOID
13 Beamforming_GidPAid(
14         PADAPTER        Adapter,
15         PRT_TCB         pTcb
16 )
17 {
18         u1Byte          Idx = 0;
19         u1Byte          RA[6] ={0};
20         pu1Byte         pHeader = GET_FRAME_OF_FIRST_FRAG(Adapter, pTcb);
21         HAL_DATA_TYPE                   *pHalData = GET_HAL_DATA(Adapter);
22         PDM_ODM_T                               pDM_Odm = &pHalData->DM_OutSrc;
23         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
24
25         if (Adapter->HardwareType < HARDWARE_TYPE_RTL8192EE)
26                 return;
27         else if (IS_WIRELESS_MODE_N(Adapter) == FALSE)
28                 return;
29
30 #if (SUPPORT_MU_BF == 1)
31         if (pTcb->TxBFPktType == RT_BF_PKT_TYPE_BROADCAST_NDPA) { /* MU NDPA */
32 #else
33         if (0) {
34 #endif
35                 /* Fill G_ID and P_AID */
36                 pTcb->G_ID = 63;
37                 if (pBeamInfo->FirstMUBFeeIndex < BEAMFORMEE_ENTRY_NUM) {
38                         pTcb->P_AID = pBeamInfo->BeamformeeEntry[pBeamInfo->FirstMUBFeeIndex].P_AID;                    
39                         RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X\n", __func__, pTcb->G_ID, pTcb->P_AID));
40                 }
41         } else {
42                 GET_80211_HDR_ADDRESS1(pHeader, &RA);
43
44                 // VHT SU PPDU carrying one or more group addressed MPDUs or
45                 // Transmitting a VHT NDP intended for multiple recipients
46                 if (MacAddr_isBcst(RA) || MacAddr_isMulticast(RA)       || pTcb->macId == MAC_ID_STATIC_FOR_BROADCAST_MULTICAST) {
47                         pTcb->G_ID = 63;
48                         pTcb->P_AID = 0;
49                 } else if (ACTING_AS_AP(Adapter)) {
50                         u2Byte  AID = (u2Byte) (MacIdGetOwnerAssociatedClientAID(Adapter, pTcb->macId) & 0x1ff);                /*AID[0:8]*/
51         
52                         /*RT_DISP(FBEAM, FBEAM_FUN, ("@%s  pTcb->macId=0x%X, AID=0x%X\n", __func__, pTcb->macId, AID));*/
53                         pTcb->G_ID = 63;
54
55                         if (AID == 0)           /*A PPDU sent by an AP to a non associated STA*/
56                                 pTcb->P_AID = 0;
57                         else {                          /*Sent by an AP and addressed to a STA associated with that AP*/
58                                 u2Byte  BSSID = 0;
59                                 GET_80211_HDR_ADDRESS2(pHeader, &RA);
60                                 BSSID = ((RA[5] & 0xf0) >> 4) ^ (RA[5] & 0xf);  /*BSSID[44:47] xor BSSID[40:43]*/
61                                 pTcb->P_AID = (AID + BSSID *32) & 0x1ff;                /*(dec(A) + dec(B)*32) mod 512*/
62                         }
63                 } else if (ACTING_AS_IBSS(Adapter)) {
64                         pTcb->G_ID = 63;
65                         /*P_AID for infrasturcture mode; MACID for ad-hoc mode. */
66                         pTcb->P_AID = pTcb->macId;
67                 } else if (MgntLinkStatusQuery(Adapter)) {                              /*Addressed to AP*/
68                         pTcb->G_ID = 0;
69                         GET_80211_HDR_ADDRESS1(pHeader, &RA);
70                         pTcb->P_AID =  RA[5];                                                   /*RA[39:47]*/
71                         pTcb->P_AID = (pTcb->P_AID << 1) | (RA[4] >> 7 );
72                 } else {
73                         pTcb->G_ID = 63;
74                         pTcb->P_AID = 0;
75                 }
76                 /*RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X\n", __func__, pTcb->G_ID, pTcb->P_AID));*/
77         }
78 }
79
80
81 RT_STATUS
82 Beamforming_GetReportFrame(
83         IN      PADAPTER                Adapter,
84         IN      PRT_RFD                 pRfd,
85         IN      POCTET_STRING   pPduOS
86         )
87 {
88         HAL_DATA_TYPE                           *pHalData = GET_HAL_DATA(Adapter);
89         PDM_ODM_T                                       pDM_Odm = &pHalData->DM_OutSrc;
90         PRT_BEAMFORMEE_ENTRY            pBeamformEntry = NULL;
91         pu1Byte                                         pMIMOCtrlField, pCSIReport, pCSIMatrix;
92         u1Byte                                          Idx, Nc, Nr, CH_W;
93         u2Byte                                          CSIMatrixLen = 0;
94
95         ACT_PKT_TYPE                            pktType = ACT_PKT_TYPE_UNKNOWN;
96
97         //Memory comparison to see if CSI report is the same with previous one
98         pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, Frame_Addr2(*pPduOS), &Idx);
99
100         if (pBeamformEntry == NULL) {
101                 ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Beamforming_GetReportFrame: Cannot find entry by addr\n"));
102                 return RT_STATUS_FAILURE;
103         }
104
105         pktType = PacketGetActionFrameType(pPduOS);
106         
107         //-@ Modified by David
108         if (pktType == ACT_PKT_VHT_COMPRESSED_BEAMFORMING) {
109                 pMIMOCtrlField = pPduOS->Octet + 26; 
110                 Nc = ((*pMIMOCtrlField) & 0x7) + 1;
111                 Nr = (((*pMIMOCtrlField) & 0x38) >> 3) + 1;
112                 CH_W =  (((*pMIMOCtrlField) & 0xC0) >> 6);
113                 pCSIMatrix = pMIMOCtrlField + 3 + Nc; //24+(1+1+3)+2  MAC header+(Category+ActionCode+MIMOControlField) +SNR(Nc=2)
114                 CSIMatrixLen = pPduOS->Length  - 26 -3 -Nc;
115         } else if (pktType == ACT_PKT_HT_COMPRESSED_BEAMFORMING) {
116                 pMIMOCtrlField = pPduOS->Octet + 26; 
117                 Nc = ((*pMIMOCtrlField) & 0x3) + 1;
118                 Nr =  (((*pMIMOCtrlField) & 0xC) >> 2) + 1;
119                 CH_W =  (((*pMIMOCtrlField) & 0x10) >> 4);
120                 pCSIMatrix = pMIMOCtrlField + 6 + Nr;   //24+(1+1+6)+2  MAC header+(Category+ActionCode+MIMOControlField) +SNR(Nc=2)
121                 CSIMatrixLen = pPduOS->Length  - 26 -6 -Nr;
122         } else
123                 return RT_STATUS_SUCCESS;       
124         
125         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] idx=%d, pkt type=%d, Nc=%d, Nr=%d, CH_W=%d\n", __func__, Idx, pktType, Nc, Nr, CH_W));              
126
127         return RT_STATUS_SUCCESS;
128 }
129
130
131 VOID
132 ConstructHTNDPAPacket(
133         PADAPTER                Adapter,
134         pu1Byte                 RA,
135         pu1Byte                 Buffer,
136         pu4Byte                 pLength,
137         CHANNEL_WIDTH   BW
138         )
139 {
140         u2Byte                                  Duration= 0;
141         PMGNT_INFO                              pMgntInfo = &(Adapter->MgntInfo);
142         OCTET_STRING                    pNDPAFrame,ActionContent;
143         u1Byte                                  ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
144
145         PlatformZeroMemory(Buffer, 32);
146
147         SET_80211_HDR_FRAME_CONTROL(Buffer,0);
148
149         SET_80211_HDR_ORDER(Buffer, 1);
150         SET_80211_HDR_TYPE_AND_SUBTYPE(Buffer,Type_Action_No_Ack);
151
152         SET_80211_HDR_ADDRESS1(Buffer, RA);
153         SET_80211_HDR_ADDRESS2(Buffer, Adapter->CurrentAddress);
154         SET_80211_HDR_ADDRESS3(Buffer, pMgntInfo->Bssid);
155
156         Duration = 2*aSifsTime + 40;
157         
158         if (BW == CHANNEL_WIDTH_40)
159                 Duration+= 87;
160         else    
161                 Duration+= 180;
162
163         SET_80211_HDR_DURATION(Buffer, Duration);
164
165         //HT control field
166         SET_HT_CTRL_CSI_STEERING(Buffer+sMacHdrLng, 3);
167         SET_HT_CTRL_NDP_ANNOUNCEMENT(Buffer+sMacHdrLng, 1);
168         
169         FillOctetString(pNDPAFrame, Buffer, sMacHdrLng+sHTCLng);
170
171         FillOctetString(ActionContent, ActionHdr, 4);
172         PacketAppendData(&pNDPAFrame, ActionContent);   
173
174         *pLength = 32;
175 }
176
177
178
179
180 BOOLEAN
181 SendFWHTNDPAPacket(
182         IN      PVOID                   pDM_VOID,
183         IN      pu1Byte                 RA,
184         IN      CHANNEL_WIDTH   BW
185         )
186 {
187         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
188         PADAPTER                                Adapter = pDM_Odm->Adapter;
189         PRT_TCB                                 pTcb;
190         PRT_TX_LOCAL_BUFFER     pBuf;
191         BOOLEAN                                 ret = TRUE;
192         u4Byte                                  BufLen;
193         pu1Byte                                 BufAddr;
194         u1Byte                                  DescLen = 0, Idx = 0, NDPTxRate;
195         PADAPTER                                pDefAdapter = GetDefaultAdapter(Adapter);
196         PRT_BEAMFORMING_INFO    pBeamInfo = &pDM_Odm->BeamformingInfo;
197         HAL_DATA_TYPE                   *pHalData = GET_HAL_DATA(Adapter);
198         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
199
200         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
201
202         if (pBeamformEntry == NULL)
203                 return FALSE;
204
205         NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
206         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
207         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
208
209         if (MgntGetFWBuffer(pDefAdapter, &pTcb, &pBuf)) {
210 #if(DEV_BUS_TYPE != RT_PCI_INTERFACE)
211                 DescLen = Adapter->HWDescHeadLength - pHalData->USBALLDummyLength;
212 #endif
213                 BufAddr = pBuf->Buffer.VirtualAddress + DescLen;
214
215                 ConstructHTNDPAPacket(
216                                 Adapter, 
217                                 RA,
218                                 BufAddr, 
219                                 &BufLen,
220                                 BW
221                                 );
222
223                 pTcb->PacketLength = BufLen + DescLen;
224
225                 pTcb->bTxEnableSwCalcDur = TRUE;
226                 
227                 pTcb->BWOfPacket = BW;
228
229                 if(ACTING_AS_IBSS(Adapter) || ACTING_AS_AP(Adapter))
230                         pTcb->G_ID = 63;
231
232                 pTcb->P_AID = pBeamformEntry->P_AID;
233                 pTcb->DataRate = NDPTxRate;     /*rate of NDP decide by Nr*/
234
235                 Adapter->HalFunc.CmdSendPacketHandler(Adapter, pTcb, pBuf, pTcb->PacketLength, DESC_PACKET_TYPE_NORMAL, FALSE);
236         } else
237                 ret = FALSE;
238
239         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
240         
241         if (ret)
242                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
243
244         return ret;
245 }
246
247
248 BOOLEAN
249 SendSWHTNDPAPacket(
250         IN      PVOID                   pDM_VOID,
251         IN      pu1Byte                 RA,
252         IN      CHANNEL_WIDTH   BW
253         )
254 {
255         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
256         PADAPTER                                Adapter = pDM_Odm->Adapter;
257         PRT_TCB                                 pTcb;
258         PRT_TX_LOCAL_BUFFER             pBuf;
259         BOOLEAN                                 ret = TRUE;
260         u1Byte                                  Idx = 0, NDPTxRate = 0;
261         PRT_BEAMFORMING_INFO    pBeamInfo = &pDM_Odm->BeamformingInfo;
262         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
263
264         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
265
266         NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
267         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
268         
269         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
270
271         if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) {
272                 ConstructHTNDPAPacket(
273                                 Adapter, 
274                                 RA,
275                                 pBuf->Buffer.VirtualAddress, 
276                                 &pTcb->PacketLength,
277                                 BW
278                                 );
279
280                 pTcb->bTxEnableSwCalcDur = TRUE;
281
282                 pTcb->BWOfPacket = BW;
283
284                 MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate);
285         } else
286                 ret = FALSE;
287         
288         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
289
290         if (ret)
291                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
292
293         return ret;
294 }
295
296
297
298 VOID
299 ConstructVHTNDPAPacket(
300         IN PDM_ODM_T    pDM_Odm,
301         pu1Byte                 RA,
302         u2Byte                  AID,
303         pu1Byte                 Buffer,
304         pu4Byte                 pLength,
305         CHANNEL_WIDTH   BW
306         )
307 {
308         u2Byte                                  Duration= 0;
309         u1Byte                                  Sequence = 0;
310         pu1Byte                                 pNDPAFrame = Buffer;
311         RT_NDPA_STA_INFO                STAInfo;
312         PADAPTER                                Adapter = pDM_Odm->Adapter;
313         u1Byte  Idx = 0;
314         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
315         // Frame control.
316         SET_80211_HDR_FRAME_CONTROL(pNDPAFrame, 0);
317         SET_80211_HDR_TYPE_AND_SUBTYPE(pNDPAFrame, Type_NDPA);
318
319         SET_80211_HDR_ADDRESS1(pNDPAFrame, RA);
320         SET_80211_HDR_ADDRESS2(pNDPAFrame, pBeamformEntry->MyMacAddr);
321
322         Duration = 2*aSifsTime + 44;
323         
324         if (BW == CHANNEL_WIDTH_80)
325                 Duration += 40;
326         else if(BW == CHANNEL_WIDTH_40)
327                 Duration+= 87;
328         else    
329                 Duration+= 180;
330
331         SET_80211_HDR_DURATION(pNDPAFrame, Duration);
332
333         Sequence = *(pDM_Odm->pSoundingSeq) << 2;
334         ODM_MoveMemory(pDM_Odm, pNDPAFrame+16, &Sequence, 1);
335
336         if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_IBSS) || phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP) == FALSE)
337                 AID = 0;
338
339         STAInfo.AID = AID;
340         STAInfo.FeedbackType = 0;
341         STAInfo.NcIndex = 0;
342         
343         ODM_MoveMemory(pDM_Odm, pNDPAFrame+17, (pu1Byte)&STAInfo, 2);
344
345         *pLength = 19;
346 }
347
348
349 BOOLEAN
350 SendFWVHTNDPAPacket(
351         IN      PVOID                   pDM_VOID,
352         IN      pu1Byte                 RA,
353         IN      u2Byte                  AID,
354         IN      CHANNEL_WIDTH   BW
355         )
356 {
357         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
358         PADAPTER                                Adapter = pDM_Odm->Adapter;
359         PRT_TCB                                 pTcb;
360         PRT_TX_LOCAL_BUFFER             pBuf;
361         BOOLEAN                                 ret = TRUE;
362         u4Byte                                  BufLen;
363         pu1Byte                                 BufAddr;
364         u1Byte                                  DescLen = 0, Idx = 0, NDPTxRate = 0;
365         PADAPTER                                pDefAdapter = GetDefaultAdapter(Adapter);
366         PRT_BEAMFORMING_INFO    pBeamInfo = &pDM_Odm->BeamformingInfo;
367         HAL_DATA_TYPE                   *pHalData = GET_HAL_DATA(Adapter);
368         PRT_BEAMFORMEE_ENTRY    pBeamformEntry =phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
369
370         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
371
372         if (pBeamformEntry == NULL)
373                 return FALSE;
374
375         NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
376         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
377         
378         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
379
380         if (MgntGetFWBuffer(pDefAdapter, &pTcb, &pBuf)) {
381 #if(DEV_BUS_TYPE != RT_PCI_INTERFACE)
382                 DescLen = Adapter->HWDescHeadLength - pHalData->USBALLDummyLength;
383 #endif
384                 BufAddr = pBuf->Buffer.VirtualAddress + DescLen;
385
386                 ConstructVHTNDPAPacket(
387                                 pDM_Odm, 
388                                 RA,
389                                 AID,
390                                 BufAddr, 
391                                 &BufLen,
392                                 BW
393                                 );
394                 
395                 pTcb->PacketLength = BufLen + DescLen;
396
397                 pTcb->bTxEnableSwCalcDur = TRUE;
398                 
399                 pTcb->BWOfPacket = BW;
400
401                 if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_IBSS) || phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP))
402                         pTcb->G_ID = 63;
403
404                 pTcb->P_AID = pBeamformEntry->P_AID;
405                 pTcb->DataRate = NDPTxRate;     /*decide by Nr*/
406
407                 Adapter->HalFunc.CmdSendPacketHandler(Adapter, pTcb, pBuf, pTcb->PacketLength, DESC_PACKET_TYPE_NORMAL, FALSE);
408         } else
409                 ret = FALSE;
410         
411         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);       
412
413         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] End, ret=%d\n", __func__, ret));
414
415         if (ret)
416                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
417
418         return ret;
419 }
420
421
422
423 BOOLEAN
424 SendSWVHTNDPAPacket(
425         IN      PVOID                   pDM_VOID,
426         IN      pu1Byte                 RA,
427         IN      u2Byte                  AID,
428         IN      CHANNEL_WIDTH   BW
429         )
430 {
431         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
432         PADAPTER                                Adapter = pDM_Odm->Adapter;
433         PRT_TCB                                 pTcb;
434         PRT_TX_LOCAL_BUFFER             pBuf;
435         BOOLEAN                                 ret = TRUE;
436         u1Byte                                  Idx = 0, NDPTxRate = 0;
437         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
438         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
439
440         NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
441         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
442
443         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
444
445         if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) {
446                 ConstructVHTNDPAPacket(
447                                 pDM_Odm, 
448                                 RA,
449                                 AID,
450                                 pBuf->Buffer.VirtualAddress, 
451                                 &pTcb->PacketLength,
452                                 BW
453                                 );
454
455                 pTcb->bTxEnableSwCalcDur = TRUE;
456                 pTcb->BWOfPacket = BW;
457
458                 /*rate of NDP decide by Nr*/
459                 MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate);
460         } else
461                 ret = FALSE;
462         
463         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);       
464
465         if (ret)
466                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
467
468         return ret;
469 }
470
471 #ifdef SUPPORT_MU_BF
472 #if (SUPPORT_MU_BF == 1)
473 /*
474 // Description: On VHT GID management frame by an MU beamformee.
475 //
476 // 2015.05.20. Created by tynli.
477 */
478 RT_STATUS
479 Beamforming_GetVHTGIDMgntFrame(
480         IN      PADAPTER                Adapter,
481         IN      PRT_RFD                 pRfd,
482         IN      POCTET_STRING   pPduOS
483         )
484 {
485         HAL_DATA_TYPE   *pHalData = GET_HAL_DATA(Adapter);
486         PDM_ODM_T               pDM_Odm = &pHalData->DM_OutSrc;
487         RT_STATUS               rtStatus = RT_STATUS_SUCCESS;
488         pu1Byte                 pBuffer = NULL;
489         pu1Byte                 pRaddr = NULL;
490         u1Byte                  MemStatus[8] = {0}, UserPos[16] = {0};
491         u1Byte                  idx;
492         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
493         PRT_BEAMFORMER_ENTRY    pBeamformEntry = &pBeamInfo->BeamformerEntry[pBeamInfo->mu_ap_index];
494
495         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] On VHT GID mgnt frame!\n", __func__));              
496
497         /* Check length*/
498         if (pPduOS->Length < (FRAME_OFFSET_VHT_GID_MGNT_USER_POSITION_ARRAY+16)) {      
499                 ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Beamforming_GetVHTGIDMgntFrame(): Invalid length (%d)\n", pPduOS->Length));
500                 return RT_STATUS_INVALID_LENGTH;
501         }
502
503         /* Check RA*/
504         pRaddr = (pu1Byte)(pPduOS->Octet)+4;
505         if (!eqMacAddr(pRaddr, Adapter->CurrentAddress)) {              
506                 ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Beamforming_GetVHTGIDMgntFrame(): Drop because of RA error.\n"));
507                 return RT_STATUS_PKT_DROP;
508         }
509
510         RT_DISP_DATA(FBEAM, FBEAM_DATA, "On VHT GID Mgnt Frame ==>:\n", pPduOS->Octet, pPduOS->Length);
511
512         /*Parsing Membership Status Array*/
513         pBuffer = pPduOS->Octet + FRAME_OFFSET_VHT_GID_MGNT_MEMBERSHIP_STATUS_ARRAY;
514         for (idx = 0; idx < 8; idx++) {
515                 MemStatus[idx] = GET_VHT_GID_MGNT_INFO_MEMBERSHIP_STATUS(pBuffer+idx);
516                 pBeamformEntry->gid_valid[idx] = GET_VHT_GID_MGNT_INFO_MEMBERSHIP_STATUS(pBuffer+idx);
517         }
518
519         RT_DISP_DATA(FBEAM, FBEAM_DATA, "MemStatus: ", MemStatus, 8);
520
521         /* Parsing User Position Array*/
522         pBuffer = pPduOS->Octet + FRAME_OFFSET_VHT_GID_MGNT_USER_POSITION_ARRAY;
523         for (idx = 0; idx < 16; idx++) {
524                 UserPos[idx] = GET_VHT_GID_MGNT_INFO_USER_POSITION(pBuffer+idx);
525                 pBeamformEntry->user_position[idx] = GET_VHT_GID_MGNT_INFO_USER_POSITION(pBuffer+idx);
526         }
527
528         RT_DISP_DATA(FBEAM, FBEAM_DATA, "UserPos: ", UserPos, 16);
529
530         /* Group ID detail printed*/
531         {
532                 u1Byte  i, j;
533                 u1Byte  tmpVal;
534                 u2Byte  tmpVal2;
535
536                 for (i = 0; i < 8; i++) {
537                         tmpVal = MemStatus[i];
538                         tmpVal2 = ((UserPos[i*2 + 1] << 8) & 0xFF00) + (UserPos[i * 2] & 0xFF);
539                         for (j = 0; j < 8; j++) {
540                                 if ((tmpVal >> j) & BIT0) {
541                                         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Use Group ID (%d), User Position (%d)\n",
542                                                 (i*8+j), (tmpVal2 >> 2 * j)&0x3));
543                                 }
544                         }
545                 }
546         }
547
548         /* Indicate GID frame to IHV service. */
549         {
550                 u1Byte  Indibuffer[24] = {0};
551                 u1Byte  Indioffset = 0;
552                         
553                 PlatformMoveMemory(Indibuffer + Indioffset, pBeamformEntry->gid_valid, 8);
554                 Indioffset += 8;
555                 PlatformMoveMemory(Indibuffer + Indioffset, pBeamformEntry->user_position, 16);
556                 Indioffset += 16;
557
558                 PlatformIndicateCustomStatus(
559                         Adapter,
560                         RT_CUSTOM_EVENT_VHT_RECV_GID_MGNT_FRAME,
561                         RT_CUSTOM_INDI_TARGET_IHV,
562                         Indibuffer,
563                         Indioffset);
564         }
565
566         /* Config HW GID table */
567         halComTxbf_ConfigGtab(pDM_Odm);
568
569         return rtStatus;
570 }
571
572 /*
573 // Description: Construct VHT Group ID (GID) management frame.
574 //
575 // 2015.05.20. Created by tynli.
576 */
577 VOID
578 ConstructVHTGIDMgntFrame(
579         IN      PDM_ODM_T               pDM_Odm,
580         IN      pu1Byte                 RA,
581         IN      PRT_BEAMFORMEE_ENTRY    pBeamformEntry,
582         OUT     pu1Byte                 Buffer,
583         OUT     pu4Byte                 pLength
584         
585 )
586 {
587         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
588         PADAPTER                                Adapter = pBeamInfo->SourceAdapter;
589         OCTET_STRING            osFTMFrame, tmp;
590
591         FillOctetString(osFTMFrame, Buffer, 0);
592         *pLength = 0;
593
594         ConstructMaFrameHdr(
595                                         Adapter, 
596                                         RA, 
597                                         ACT_CAT_VHT, 
598                                         ACT_VHT_GROUPID_MANAGEMENT, 
599                                         &osFTMFrame);
600
601         /* Membership Status Array*/
602         FillOctetString(tmp, pBeamformEntry->gid_valid, 8);
603         PacketAppendData(&osFTMFrame, tmp);
604
605         /* User Position Array*/
606         FillOctetString(tmp, pBeamformEntry->user_position, 16);
607         PacketAppendData(&osFTMFrame, tmp);
608
609         *pLength = osFTMFrame.Length;
610
611         RT_DISP_DATA(FBEAM, FBEAM_DATA, "ConstructVHTGIDMgntFrame():\n", Buffer, *pLength);
612 }
613
614 BOOLEAN
615 SendSWVHTGIDMgntFrame(
616         IN      PVOID                   pDM_VOID,
617         IN      pu1Byte                 RA,
618         IN      u1Byte                  Idx
619         )
620 {
621         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
622         PRT_TCB                                 pTcb;
623         PRT_TX_LOCAL_BUFFER             pBuf;
624         BOOLEAN                                 ret = TRUE;
625         u1Byte                                  DataRate = 0;
626         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
627         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = &pBeamInfo->BeamformeeEntry[Idx];
628         PADAPTER                                Adapter = pBeamInfo->SourceAdapter;
629
630         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
631         
632         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
633
634         if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) {
635                 ConstructVHTGIDMgntFrame(
636                                 pDM_Odm, 
637                                 RA,
638                                 pBeamformEntry,
639                                 pBuf->Buffer.VirtualAddress, 
640                                 &pTcb->PacketLength
641                                 );
642
643                 pTcb->BWOfPacket = CHANNEL_WIDTH_20;
644                 DataRate = MGN_6M;
645                 MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, DataRate);
646         } else
647                 ret = FALSE;
648         
649         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
650
651         if (ret)
652                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
653
654         return ret;
655 }
656
657
658 /*
659 // Description: Construct VHT beamforming report poll.
660 //
661 // 2015.05.20. Created by tynli.
662 */
663 VOID
664 ConstructVHTBFReportPoll(
665         IN      PDM_ODM_T               pDM_Odm,
666         IN      pu1Byte                 RA,
667         OUT     pu1Byte                 Buffer,
668         OUT     pu4Byte                 pLength
669 )
670 {
671         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
672         PADAPTER                                Adapter = pBeamInfo->SourceAdapter;
673         pu1Byte                 pBFRptPoll = Buffer;
674         
675         /* Frame control*/
676         SET_80211_HDR_FRAME_CONTROL(pBFRptPoll, 0);
677         SET_80211_HDR_TYPE_AND_SUBTYPE(pBFRptPoll, Type_Beamforming_Report_Poll);
678
679         /* Duration*/   
680         SET_80211_HDR_DURATION(pBFRptPoll, 100);
681
682         /* RA*/
683         SET_VHT_BF_REPORT_POLL_RA(pBFRptPoll, RA);
684
685         /* TA*/
686         SET_VHT_BF_REPORT_POLL_TA(pBFRptPoll, Adapter->CurrentAddress);
687
688         /* Feedback Segment Retransmission Bitmap*/
689         SET_VHT_BF_REPORT_POLL_FEEDBACK_SEG_RETRAN_BITMAP(pBFRptPoll, 0xFF);
690
691         *pLength = 17;
692
693         RT_DISP_DATA(FBEAM, FBEAM_DATA, "ConstructVHTBFReportPoll():\n", Buffer, *pLength);
694
695 }
696
697 BOOLEAN
698 SendSWVHTBFReportPoll(
699         IN      PVOID                   pDM_VOID,
700         IN      pu1Byte                 RA,
701         IN      BOOLEAN                 bFinalPoll
702         )
703 {
704         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
705         PRT_TCB                                 pTcb;
706         PRT_TX_LOCAL_BUFFER             pBuf;
707         BOOLEAN                                 ret = TRUE;
708         u1Byte                                  Idx = 0, DataRate = 0;
709         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
710         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
711         PADAPTER                                Adapter = pBeamInfo->SourceAdapter;
712
713         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__));
714
715         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
716
717         if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) {
718                 ConstructVHTBFReportPoll(
719                                 pDM_Odm, 
720                                 RA,
721                                 pBuf->Buffer.VirtualAddress, 
722                                 &pTcb->PacketLength
723                                 );
724
725                 pTcb->bTxEnableSwCalcDur = TRUE; /* <tynli_note> need?*/
726                 pTcb->BWOfPacket = CHANNEL_WIDTH_20;
727
728                 if (bFinalPoll)
729                         pTcb->TxBFPktType = RT_BF_PKT_TYPE_FINAL_BF_REPORT_POLL;
730                 else
731                         pTcb->TxBFPktType = RT_BF_PKT_TYPE_BF_REPORT_POLL;
732                 
733                 DataRate = MGN_6M;      /* Legacy OFDM rate*/
734                 MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, DataRate);
735         } else
736                 ret = FALSE;
737         
738         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
739
740         if (ret)
741                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "SendSWVHTBFReportPoll():\n", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
742
743         return ret;
744
745 }
746
747
748 /*
749 // Description: Construct VHT MU NDPA packet.
750 //      <Note> We should combine this function with ConstructVHTNDPAPacket() in the future.
751 //
752 // 2015.05.21. Created by tynli.
753 */
754 VOID
755 ConstructVHTMUNDPAPacket(
756         IN PDM_ODM_T            pDM_Odm,
757         IN CHANNEL_WIDTH        BW,
758         OUT pu1Byte                     Buffer,
759         OUT pu4Byte                     pLength
760         )
761 {       
762         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
763         PADAPTER                                Adapter = pBeamInfo->SourceAdapter;
764         u2Byte                                  Duration = 0;
765         u1Byte                                  Sequence = 0;
766         pu1Byte                                 pNDPAFrame = Buffer;
767         RT_NDPA_STA_INFO                STAInfo;
768         u1Byte                                  idx;
769         u1Byte                                  DestAddr[6] = {0};
770         PRT_BEAMFORMEE_ENTRY    pEntry = NULL;
771
772         /* Fill the first MU BFee entry (STA1) MAC addr to destination address then
773              HW will change A1 to broadcast addr. 2015.05.28. Suggested by SD1 Chunchu. */
774         for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {              
775                 pEntry = &(pBeamInfo->BeamformeeEntry[idx]);
776                 if (pEntry->is_mu_sta) {
777                         cpMacAddr(DestAddr, pEntry->MacAddr);
778                         break;
779                 }
780         }
781         if (pEntry == NULL)
782                 return;
783
784         /* Frame control.*/
785         SET_80211_HDR_FRAME_CONTROL(pNDPAFrame, 0);
786         SET_80211_HDR_TYPE_AND_SUBTYPE(pNDPAFrame, Type_NDPA);
787
788         SET_80211_HDR_ADDRESS1(pNDPAFrame, DestAddr);
789         SET_80211_HDR_ADDRESS2(pNDPAFrame, pEntry->MyMacAddr);
790
791         /*--------------------------------------------*/
792         /* <Note> Need to modify "Duration" to MU consideration. */
793         Duration = 2*aSifsTime + 44;
794         
795         if (BW == CHANNEL_WIDTH_80)
796                 Duration += 40;
797         else if(BW == CHANNEL_WIDTH_40)
798                 Duration+= 87;
799         else    
800                 Duration+= 180;
801         /*--------------------------------------------*/
802
803         SET_80211_HDR_DURATION(pNDPAFrame, Duration);
804
805         Sequence = *(pDM_Odm->pSoundingSeq) << 2;
806         ODM_MoveMemory(pDM_Odm, pNDPAFrame + 16, &Sequence, 1);
807
808         *pLength = 17;
809
810         /* Construct STA info. for multiple STAs*/
811         for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {              
812                 pEntry = &(pBeamInfo->BeamformeeEntry[idx]);
813                 if (pEntry->is_mu_sta) {
814                         STAInfo.AID = pEntry->AID;
815                         STAInfo.FeedbackType = 1; /* 1'b1: MU*/
816                         STAInfo.NcIndex = 0;
817
818                         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Get BeamformeeEntry idx(%d), AID =%d\n", __func__, idx, pEntry->AID));
819                         
820                         ODM_MoveMemory(pDM_Odm, pNDPAFrame+(*pLength), (pu1Byte)&STAInfo, 2);
821                         *pLength += 2;
822                 }
823         }
824
825 }
826
827 BOOLEAN
828 SendSWVHTMUNDPAPacket(
829         IN      PVOID                   pDM_VOID,
830         IN      CHANNEL_WIDTH   BW
831         )
832 {
833         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
834         PRT_TCB                                 pTcb;
835         PRT_TX_LOCAL_BUFFER             pBuf;
836         BOOLEAN                                 ret = TRUE;
837         u1Byte                                  NDPTxRate = 0;
838         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
839         PADAPTER                                Adapter = pBeamInfo->SourceAdapter;
840
841         NDPTxRate = MGN_VHT2SS_MCS0;
842         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
843
844         PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
845
846         if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) {
847                 ConstructVHTMUNDPAPacket(
848                                 pDM_Odm,
849                                 BW,
850                                 pBuf->Buffer.VirtualAddress, 
851                                 &pTcb->PacketLength
852                                 );
853
854                 pTcb->bTxEnableSwCalcDur = TRUE;
855                 pTcb->BWOfPacket = BW;
856                 pTcb->TxBFPktType = RT_BF_PKT_TYPE_BROADCAST_NDPA;
857
858                 /*rate of NDP decide by Nr*/
859                 MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate);
860         } else
861                 ret = FALSE;
862         
863         PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);       
864
865         if (ret)
866                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength);
867
868         return ret;
869 }
870
871 #endif  /*#if (SUPPORT_MU_BF == 1)*/
872 #endif  /*#ifdef SUPPORT_MU_BF*/
873
874
875 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
876
877 u4Byte
878 Beamforming_GetReportFrame(
879         IN      PVOID                   pDM_VOID,
880         union recv_frame *precv_frame
881         )
882 {
883         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
884         u4Byte                                  ret = _SUCCESS;
885         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = NULL;
886         pu1Byte                                 pframe = precv_frame->u.hdr.rx_data;
887         u4Byte                                  frame_len = precv_frame->u.hdr.len;
888         pu1Byte                                 TA;
889         u1Byte                                  Idx, offset;
890         
891         /*DBG_871X("beamforming_get_report_frame\n");*/
892
893         /*Memory comparison to see if CSI report is the same with previous one*/
894         TA = GetAddr2Ptr(pframe);
895         pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, TA, &Idx);
896         if(pBeamformEntry->BeamformEntryCap & BEAMFORMER_CAP_VHT_SU)
897                 offset = 31;            /*24+(1+1+3)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/
898         else if(pBeamformEntry->BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT)
899                 offset = 34;            /*24+(1+1+6)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/
900         else
901                 return ret;
902
903         /*DBG_871X("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);*/
904         
905         return ret;
906 }
907
908
909 BOOLEAN
910 SendFWHTNDPAPacket(
911         IN      PVOID                   pDM_VOID,
912         IN      pu1Byte                 RA,
913         IN      CHANNEL_WIDTH   BW
914         )
915 {
916         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
917         PADAPTER                                Adapter = pDM_Odm->Adapter;
918         struct xmit_frame               *pmgntframe;
919         struct pkt_attrib               *pattrib;
920         struct rtw_ieee80211_hdr        *pwlanhdr;
921         struct xmit_priv                *pxmitpriv = &(Adapter->xmitpriv);
922         struct mlme_ext_priv    *pmlmeext = &Adapter->mlmeextpriv;
923         struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
924         u1Byte  ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
925         u1Byte  *pframe;
926         u2Byte  *fctrl;
927         u2Byte  duration = 0;
928         u1Byte  aSifsTime = 0, NDPTxRate = 0, Idx = 0;
929         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
930         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
931
932         pmgntframe = alloc_mgtxmitframe(pxmitpriv);
933         
934         if (pmgntframe == NULL) {
935                 DBG_871X("%s, alloc mgnt frame fail\n", __func__);
936                 return _FALSE;
937         }
938
939         //update attribute
940         pattrib = &pmgntframe->attrib;
941         update_mgntframe_attrib(Adapter, pattrib);
942
943         pattrib->qsel = QSLT_BEACON;
944         NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
945         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
946         pattrib->rate = NDPTxRate;
947         pattrib->bwmode = BW;
948         pattrib->order = 1;
949         pattrib->subtype = WIFI_ACTION_NOACK;
950
951         _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
952
953         pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
954
955         pwlanhdr = (struct rtw_ieee80211_hdr*)pframe;
956
957         fctrl = &pwlanhdr->frame_ctl;
958         *(fctrl) = 0;
959
960         SetOrderBit(pframe);
961         SetFrameSubType(pframe, WIFI_ACTION_NOACK);
962
963         _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
964         _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN);
965         _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
966
967         if( pmlmeext->cur_wireless_mode == WIRELESS_11B)
968                 aSifsTime = 10;
969         else
970                 aSifsTime = 16;
971
972         duration = 2*aSifsTime + 40;
973         
974         if(BW == CHANNEL_WIDTH_40)
975                 duration+= 87;
976         else    
977                 duration+= 180;
978
979         SetDuration(pframe, duration);
980
981         //HT control field
982         SET_HT_CTRL_CSI_STEERING(pframe+24, 3);
983         SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe+24, 1);
984
985         _rtw_memcpy(pframe+28, ActionHdr, 4);
986
987         pattrib->pktlen = 32;
988
989         pattrib->last_txcmdsz = pattrib->pktlen;
990
991         dump_mgntframe(Adapter, pmgntframe);
992
993         return _TRUE;
994 }
995
996
997 BOOLEAN
998 SendSWHTNDPAPacket(
999         IN      PVOID                   pDM_VOID,
1000         IN      pu1Byte                 RA,
1001         IN      CHANNEL_WIDTH   BW
1002         )
1003 {
1004         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
1005         PADAPTER                                Adapter = pDM_Odm->Adapter;
1006         struct xmit_frame               *pmgntframe;
1007         struct pkt_attrib               *pattrib;
1008         struct rtw_ieee80211_hdr        *pwlanhdr;
1009         struct xmit_priv                *pxmitpriv = &(Adapter->xmitpriv);
1010         struct mlme_ext_priv    *pmlmeext = &Adapter->mlmeextpriv;
1011         struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
1012         u1Byte  ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
1013         pu1Byte pframe;
1014         pu2Byte fctrl;
1015         u2Byte  duration = 0;
1016         u1Byte  aSifsTime = 0, NDPTxRate = 0, Idx = 0;
1017         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
1018         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
1019
1020         NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
1021         
1022         pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1023         
1024         if (pmgntframe == NULL) {
1025                 DBG_871X("%s, alloc mgnt frame fail\n", __func__);
1026                 return _FALSE;
1027         }
1028
1029         /*update attribute*/
1030         pattrib = &pmgntframe->attrib;
1031         update_mgntframe_attrib(Adapter, pattrib);
1032         pattrib->qsel = QSLT_MGNT;
1033         pattrib->rate = NDPTxRate;
1034         pattrib->bwmode = BW;
1035         pattrib->order = 1;
1036         pattrib->subtype = WIFI_ACTION_NOACK;
1037
1038         _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1039
1040         pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1041
1042         pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1043
1044         fctrl = &pwlanhdr->frame_ctl;
1045         *(fctrl) = 0;
1046
1047         SetOrderBit(pframe);
1048         SetFrameSubType(pframe, WIFI_ACTION_NOACK);
1049
1050         _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1051         _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN);
1052         _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
1053
1054         if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
1055                 aSifsTime = 10;
1056         else
1057                 aSifsTime = 16;
1058
1059         duration = 2*aSifsTime + 40;
1060         
1061         if (BW == CHANNEL_WIDTH_40)
1062                 duration += 87;
1063         else    
1064                 duration += 180;
1065
1066         SetDuration(pframe, duration);
1067
1068         /*HT control field*/
1069         SET_HT_CTRL_CSI_STEERING(pframe+24, 3);
1070         SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe+24, 1);
1071
1072         _rtw_memcpy(pframe+28, ActionHdr, 4);
1073
1074         pattrib->pktlen = 32;
1075
1076         pattrib->last_txcmdsz = pattrib->pktlen;
1077
1078         dump_mgntframe(Adapter, pmgntframe);
1079
1080         return _TRUE;
1081 }
1082
1083
1084 BOOLEAN
1085 SendFWVHTNDPAPacket(
1086         IN      PVOID                   pDM_VOID,
1087         IN      pu1Byte                 RA,
1088         IN      u2Byte                  AID,
1089         IN      CHANNEL_WIDTH   BW
1090         )
1091 {
1092         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
1093         PADAPTER                                Adapter = pDM_Odm->Adapter;
1094         struct xmit_frame               *pmgntframe;
1095         struct pkt_attrib               *pattrib;
1096         struct rtw_ieee80211_hdr        *pwlanhdr;
1097         struct xmit_priv                *pxmitpriv = &(Adapter->xmitpriv);
1098         struct mlme_ext_priv    *pmlmeext = &Adapter->mlmeextpriv;
1099         struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
1100         struct mlme_priv                *pmlmepriv = &(Adapter->mlmepriv);
1101         pu1Byte pframe;
1102         pu2Byte fctrl;
1103         u2Byte  duration = 0;
1104         u1Byte  sequence = 0, aSifsTime = 0, NDPTxRate= 0, Idx = 0;
1105         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
1106         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
1107         RT_NDPA_STA_INFO        sta_info;
1108
1109         pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1110         
1111         if (pmgntframe == NULL) {
1112                 DBG_871X("%s, alloc mgnt frame fail\n", __func__);
1113                 return _FALSE;
1114         }
1115
1116         //update attribute
1117         pattrib = &pmgntframe->attrib;
1118         _rtw_memcpy(pattrib->ra, RA, ETH_ALEN);
1119         update_mgntframe_attrib(Adapter, pattrib);
1120
1121         pattrib->qsel = QSLT_BEACON;
1122         NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
1123         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
1124         pattrib->rate = NDPTxRate;
1125         pattrib->bwmode = BW;
1126         pattrib->subtype = WIFI_NDPA;
1127
1128         _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1129
1130         pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1131
1132         pwlanhdr = (struct rtw_ieee80211_hdr*)pframe;
1133
1134         fctrl = &pwlanhdr->frame_ctl;
1135         *(fctrl) = 0;
1136
1137         SetFrameSubType(pframe, WIFI_NDPA);
1138
1139         _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1140         _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN);
1141
1142         if (IsSupported5G(pmlmeext->cur_wireless_mode) || IsSupportedHT(pmlmeext->cur_wireless_mode))
1143                 aSifsTime = 16;
1144         else
1145                 aSifsTime = 10;
1146
1147         duration = 2*aSifsTime + 44;
1148         
1149         if(BW == CHANNEL_WIDTH_80)
1150                 duration += 40;
1151         else if(BW == CHANNEL_WIDTH_40)
1152                 duration+= 87;
1153         else    
1154                 duration+= 180;
1155
1156         SetDuration(pframe, duration);
1157
1158         sequence = pBeamInfo->SoundingSequence<< 2;
1159         if (pBeamInfo->SoundingSequence >= 0x3f)
1160                 pBeamInfo->SoundingSequence = 0;
1161         else
1162                 pBeamInfo->SoundingSequence++;
1163
1164         _rtw_memcpy(pframe+16, &sequence,1);
1165
1166         if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
1167                 AID = 0;                
1168
1169         sta_info.AID = AID;
1170         sta_info.FeedbackType = 0;
1171         sta_info.NcIndex= 0;
1172         
1173         _rtw_memcpy(pframe+17, (u8 *)&sta_info, 2);
1174
1175         pattrib->pktlen = 19;
1176
1177         pattrib->last_txcmdsz = pattrib->pktlen;
1178
1179         dump_mgntframe(Adapter, pmgntframe);
1180
1181         return _TRUE;
1182 }
1183
1184
1185
1186 BOOLEAN
1187 SendSWVHTNDPAPacket(
1188         IN      PVOID                   pDM_VOID,
1189         IN      pu1Byte                 RA,
1190         IN      u2Byte                  AID,
1191         IN      CHANNEL_WIDTH   BW
1192         )
1193 {
1194         PDM_ODM_T                               pDM_Odm = (PDM_ODM_T)pDM_VOID;
1195         PADAPTER                                Adapter = pDM_Odm->Adapter;
1196         struct xmit_frame               *pmgntframe;
1197         struct pkt_attrib               *pattrib;
1198         struct rtw_ieee80211_hdr        *pwlanhdr;
1199         struct xmit_priv                *pxmitpriv = &(Adapter->xmitpriv);
1200         struct mlme_ext_priv    *pmlmeext = &Adapter->mlmeextpriv;
1201         struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
1202         struct mlme_priv                *pmlmepriv = &(Adapter->mlmepriv);
1203         RT_NDPA_STA_INFO        ndpa_sta_info;
1204         u1Byte  NDPTxRate = 0, sequence = 0, aSifsTime = 0, Idx = 0;
1205         pu1Byte pframe;
1206         pu2Byte fctrl;
1207         u2Byte  duration = 0;
1208         PRT_BEAMFORMING_INFO    pBeamInfo = &(pDM_Odm->BeamformingInfo);
1209         PRT_BEAMFORMEE_ENTRY    pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx);
1210
1211         NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer);
1212         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate));
1213
1214         pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1215         
1216         if (pmgntframe == NULL) {
1217                 DBG_871X("%s, alloc mgnt frame fail\n", __func__);
1218                 return _FALSE;
1219         }
1220         
1221         /*update attribute*/
1222         pattrib = &pmgntframe->attrib;
1223         _rtw_memcpy(pattrib->ra, RA, ETH_ALEN);
1224         update_mgntframe_attrib(Adapter, pattrib);
1225         pattrib->qsel = QSLT_MGNT;
1226         pattrib->rate = NDPTxRate;
1227         pattrib->bwmode = BW;
1228         pattrib->subtype = WIFI_NDPA;
1229
1230         _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1231
1232         pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1233
1234         pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1235
1236         fctrl = &pwlanhdr->frame_ctl;
1237         *(fctrl) = 0;
1238
1239         SetFrameSubType(pframe, WIFI_NDPA);
1240
1241         _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1242         _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN);
1243
1244         if (IsSupported5G(pmlmeext->cur_wireless_mode) || IsSupportedHT(pmlmeext->cur_wireless_mode))
1245                 aSifsTime = 16;
1246         else
1247                 aSifsTime = 10;
1248
1249         duration = 2*aSifsTime + 44;
1250         
1251         if (BW == CHANNEL_WIDTH_80)
1252                 duration += 40;
1253         else if (BW == CHANNEL_WIDTH_40)
1254                 duration += 87;
1255         else    
1256                 duration += 180;
1257
1258         SetDuration(pframe, duration);
1259         
1260         sequence = pBeamInfo->SoundingSequence << 2;
1261         if (pBeamInfo->SoundingSequence >= 0x3f)
1262                 pBeamInfo->SoundingSequence = 0;
1263         else
1264                 pBeamInfo->SoundingSequence++;
1265
1266         _rtw_memcpy(pframe+16, &sequence, 1);
1267         if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
1268                 AID = 0;                
1269
1270         ndpa_sta_info.AID = AID;
1271         ndpa_sta_info.FeedbackType = 0;
1272         ndpa_sta_info.NcIndex = 0;
1273         
1274         _rtw_memcpy(pframe+17, (u8 *)&ndpa_sta_info, 2);
1275
1276         pattrib->pktlen = 19;
1277
1278         pattrib->last_txcmdsz = pattrib->pktlen;
1279
1280         dump_mgntframe(Adapter, pmgntframe);
1281         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] [%d]\n", __func__, __LINE__));
1282         
1283         return _TRUE;
1284 }
1285
1286
1287 #endif
1288
1289
1290 VOID
1291 Beamforming_GetNDPAFrame(
1292         IN      PVOID                   pDM_VOID,
1293 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1294         IN      OCTET_STRING    pduOS
1295 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1296         union recv_frame *precv_frame
1297 #endif
1298 )
1299 {
1300         PDM_ODM_T                                       pDM_Odm = (PDM_ODM_T)pDM_VOID;
1301         PADAPTER                                        Adapter = pDM_Odm->Adapter;
1302         pu1Byte                                         TA ;
1303         u1Byte                                          Idx, Sequence;
1304 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1305         pu1Byte                                         pNDPAFrame = pduOS.Octet;
1306 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1307         pu1Byte                                         pNDPAFrame = precv_frame->u.hdr.rx_data;
1308 #endif
1309         PRT_BEAMFORMER_ENTRY            pBeamformerEntry = NULL;                /*Modified By Jeffery @2014-10-29*/
1310         
1311
1312 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1313                 RT_DISP_DATA(FBEAM, FBEAM_DATA, "Beamforming_GetNDPAFrame\n", pduOS.Octet, pduOS.Length);
1314         if (IsCtrlNDPA(pNDPAFrame) == FALSE)
1315 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1316         if (GetFrameSubType(pNDPAFrame) != WIFI_NDPA)
1317 #endif
1318                 return;
1319         else if (!(pDM_Odm->SupportICType & (ODM_RTL8812 | ODM_RTL8821))) {
1320                 ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] not 8812 or 8821A, return\n", __func__));
1321                 return;
1322         }
1323 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1324         TA = Frame_Addr2(pduOS);
1325 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1326         TA = GetAddr2Ptr(pNDPAFrame);
1327 #endif
1328         /*Remove signaling TA. */
1329         TA[0] = TA[0] & 0xFE;
1330     
1331         pBeamformerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, TA, &Idx);             // Modified By Jeffery @2014-10-29
1332
1333         /*Break options for Clock Reset*/    
1334         if (pBeamformerEntry == NULL)
1335                 return;
1336         else if (!(pBeamformerEntry->BeamformEntryCap & BEAMFORMEE_CAP_VHT_SU))
1337                 return;
1338         /*LogSuccess: As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is NO LONGER needed !2015-04-10, Jeffery*/
1339         /*ClockResetTimes: While BFer entry always doesn't receive our CSI, clock will reset again and again.So ClockResetTimes is limited to 5 times.2015-04-13, Jeffery*/
1340         else if ((pBeamformerEntry->LogSuccess == 1) || (pBeamformerEntry->ClockResetTimes == 5)) {
1341                 ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, LogSuccess=%d, ClockResetTimes=%d, clock reset is no longer needed.\n", 
1342                         __func__, pBeamformerEntry->LogSeq, pBeamformerEntry->PreLogSeq, pBeamformerEntry->LogRetryCnt, pBeamformerEntry->LogSuccess, pBeamformerEntry->ClockResetTimes));
1343
1344         return;
1345         }
1346
1347         Sequence = (pNDPAFrame[16]) >> 2;
1348
1349         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start, Sequence=%d, LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, ClockResetTimes=%d, LogSuccess=%d\n", 
1350                 __func__, Sequence, pBeamformerEntry->LogSeq, pBeamformerEntry->PreLogSeq, pBeamformerEntry->LogRetryCnt, pBeamformerEntry->ClockResetTimes, pBeamformerEntry->LogSuccess));
1351
1352         if ((pBeamformerEntry->LogSeq != 0) && (pBeamformerEntry->PreLogSeq != 0)) {
1353                 /*Success condition*/
1354                 if ((pBeamformerEntry->LogSeq != Sequence) && (pBeamformerEntry->PreLogSeq != pBeamformerEntry->LogSeq)) {
1355                         /* break option for clcok reset, 2015-03-30, Jeffery */
1356                         pBeamformerEntry->LogRetryCnt = 0;
1357                         /*As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is no longer needed.*/
1358                         /*That is, LogSuccess is NOT needed to be reset to zero, 2015-04-13, Jeffery*/
1359                         pBeamformerEntry->LogSuccess = 1;
1360
1361                 } else {/*Fail condition*/
1362
1363                         if (pBeamformerEntry->LogRetryCnt == 5) {
1364                                 pBeamformerEntry->ClockResetTimes++;
1365                                 pBeamformerEntry->LogRetryCnt = 0;
1366
1367                         ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Clock Reset!!! ClockResetTimes=%d\n", 
1368                                 __func__, pBeamformerEntry->ClockResetTimes));
1369                         HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_CLK, NULL);
1370
1371                         } else
1372                                 pBeamformerEntry->LogRetryCnt++;
1373                 }
1374         }
1375
1376         /*Update LogSeq & PreLogSeq*/
1377         pBeamformerEntry->PreLogSeq = pBeamformerEntry->LogSeq;
1378         pBeamformerEntry->LogSeq = Sequence;
1379         
1380 }
1381
1382
1383
1384 #endif