1 /******************************************************************************
\r
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
\r
5 * This program is free software; you can redistribute it and/or modify it
\r
6 * under the terms of version 2 of the GNU General Public License as
\r
7 * published by the Free Software Foundation.
\r
9 * This program is distributed in the hope that it will be useful, but WITHOUT
\r
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
14 * You should have received a copy of the GNU General Public License along with
\r
15 * this program; if not, write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
\r
19 ******************************************************************************/
\r
20 #define _RTW_BEAMFORMING_C_
\r
22 #include <drv_types.h>
\r
23 #include <hal_data.h>
\r
25 #ifdef CONFIG_BEAMFORMING
\r
27 struct beamforming_entry *beamforming_get_entry_by_addr(struct mlme_priv *pmlmepriv, u8* ra,u8* idx)
\r
30 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
32 for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
\r
34 if( pBeamInfo->beamforming_entry[i].bUsed &&
\r
35 (_rtw_memcmp(ra,pBeamInfo->beamforming_entry[i].mac_addr, ETH_ALEN)))
\r
38 return &(pBeamInfo->beamforming_entry[i]);
\r
45 BEAMFORMING_CAP beamforming_get_entry_beam_cap_by_mac_id(PVOID pmlmepriv ,u8 mac_id)
\r
48 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((struct mlme_priv *)pmlmepriv);
\r
49 BEAMFORMING_CAP BeamformEntryCap = BEAMFORMING_CAP_NONE;
\r
51 for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
\r
53 if( pBeamInfo->beamforming_entry[i].bUsed &&
\r
54 (mac_id == pBeamInfo->beamforming_entry[i].mac_id))
\r
56 BeamformEntryCap = pBeamInfo->beamforming_entry[i].beamforming_entry_cap;
\r
57 i = BEAMFORMING_ENTRY_NUM;
\r
61 return BeamformEntryCap;
\r
64 struct beamforming_entry *beamforming_get_free_entry(struct mlme_priv *pmlmepriv, u8* idx)
\r
67 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
69 for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
\r
71 if(pBeamInfo->beamforming_entry[i].bUsed == _FALSE)
\r
74 return &(pBeamInfo->beamforming_entry[i]);
\r
81 struct beamforming_entry *beamforming_add_entry(PADAPTER adapter, u8* ra, u16 aid,
\r
82 u16 mac_id, CHANNEL_WIDTH bw, BEAMFORMING_CAP beamfrom_cap, u8* idx)
\r
84 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
85 struct beamforming_entry *pEntry = beamforming_get_free_entry(pmlmepriv, idx);
\r
89 pEntry->bUsed = _TRUE;
\r
91 pEntry->mac_id = mac_id;
\r
92 pEntry->sound_bw = bw;
\r
93 if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
\r
95 u16 BSSID = ((adapter->eeprompriv.mac_addr[5] & 0xf0) >> 4) ^
\r
96 (adapter->eeprompriv.mac_addr[5] & 0xf); // BSSID[44:47] xor BSSID[40:43]
\r
97 pEntry->p_aid = (aid + BSSID * 32) & 0x1ff; // (dec(A) + dec(B)*32) mod 512
\r
99 else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
\r
105 pEntry->p_aid = ra[5]; // BSSID[39:47]
\r
106 pEntry->p_aid = (pEntry->p_aid << 1) | (ra[4] >> 7 );
\r
108 _rtw_memcpy(pEntry->mac_addr, ra, ETH_ALEN);
\r
109 pEntry->bSound = _FALSE;
\r
111 //3 TODO SW/FW sound period
\r
112 pEntry->sound_period = 200;
\r
113 pEntry->beamforming_entry_cap = beamfrom_cap;
\r
114 pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
\r
116 pEntry->LogSeq = 0xff;
\r
117 pEntry->LogRetryCnt = 0;
\r
118 pEntry->LogSuccessCnt = 0;
\r
119 pEntry->LogStatusFailCnt = 0;
\r
127 BOOLEAN beamforming_remove_entry(struct mlme_priv *pmlmepriv, u8* ra, u8* idx)
\r
129 struct beamforming_entry *pEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx);
\r
133 pEntry->bUsed = _FALSE;
\r
134 pEntry->beamforming_entry_cap = BEAMFORMING_CAP_NONE;
\r
135 pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
\r
142 /* Used for BeamformingStart_V1 */
\r
143 void beamforming_dym_ndpa_rate(PADAPTER adapter)
\r
145 u16 NDPARate = MGN_6M;
\r
146 PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter);
\r
148 if(pHalData->dmpriv.MinUndecoratedPWDBForDM > 30) // link RSSI > 30%
\r
149 NDPARate = MGN_24M;
\r
153 //BW = CHANNEL_WIDTH_20;
\r
154 NDPARate = NDPARate << 8;
\r
155 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_RATE, (u8 *)&NDPARate);
\r
158 void beamforming_dym_period(PADAPTER Adapter)
\r
161 BOOLEAN bChangePeriod = _FALSE;
\r
162 u16 SoundPeriod_SW, SoundPeriod_FW;
\r
163 PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
\r
164 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
\r
165 struct beamforming_entry *pBeamformEntry;
\r
166 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(( &Adapter->mlmepriv));
\r
167 struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info);
\r
169 //3 TODO per-client throughput caculation.
\r
171 if(pdvobjpriv->traffic_stat.cur_tx_tp + pdvobjpriv->traffic_stat.cur_rx_tp > 2)
\r
173 SoundPeriod_SW = 32*20;
\r
174 SoundPeriod_FW = 2;
\r
178 SoundPeriod_SW = 32*2000;
\r
179 SoundPeriod_FW = 200;
\r
182 for(Idx = 0; Idx < BEAMFORMING_ENTRY_NUM; Idx++)
\r
184 pBeamformEntry = pBeamInfo->beamforming_entry+Idx;
\r
185 if(pBeamformEntry->bDefaultCSI)
\r
187 SoundPeriod_SW = 32*2000;
\r
188 SoundPeriod_FW = 200;
\r
191 if(pBeamformEntry->beamforming_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT |BEAMFORMER_CAP_VHT_SU))
\r
193 if(pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
\r
195 if(pBeamformEntry->sound_period != SoundPeriod_FW)
\r
197 pBeamformEntry->sound_period = SoundPeriod_FW;
\r
198 bChangePeriod = _TRUE; // Only FW sounding need to send H2C packet to change sound period.
\r
201 else if(pBeamformEntry->sound_period != SoundPeriod_SW)
\r
203 pBeamformEntry->sound_period = SoundPeriod_SW;
\r
209 rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&Idx);
\r
212 u32 beamforming_get_report_frame(PADAPTER Adapter, union recv_frame *precv_frame)
\r
214 u32 ret = _SUCCESS;
\r
215 struct beamforming_entry *pBeamformEntry = NULL;
\r
216 struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
\r
217 u8 *pframe = precv_frame->u.hdr.rx_data;
\r
218 u32 frame_len = precv_frame->u.hdr.len;
\r
222 //DBG_871X("beamforming_get_report_frame\n");
\r
224 //Memory comparison to see if CSI report is the same with previous one
\r
225 ta = GetAddr2Ptr(pframe);
\r
226 pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx);
\r
227 if(pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU)
\r
228 offset = 31; //24+(1+1+3)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
\r
229 else if(pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
\r
230 offset = 34; //24+(1+1+6)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
\r
234 //DBG_871X("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);
\r
236 if(_rtw_memcmp(pBeamformEntry->PreCsiReport + offset, pframe+offset, frame_len-offset) == _FALSE)
\r
238 pBeamformEntry->DefaultCsiCnt = 0;
\r
239 //DBG_871X("%s CSI report is NOT the same with previos one\n", __FUNCTION__);
\r
243 pBeamformEntry->DefaultCsiCnt ++;
\r
244 //DBG_871X("%s CSI report is the SAME with previos one\n", __FUNCTION__);
\r
246 _rtw_memcpy(&pBeamformEntry->PreCsiReport, pframe, frame_len);
\r
248 pBeamformEntry->bDefaultCSI = _FALSE;
\r
250 if(pBeamformEntry->DefaultCsiCnt > 20)
\r
251 pBeamformEntry->bDefaultCSI = _TRUE;
\r
253 pBeamformEntry->bDefaultCSI = _FALSE;
\r
258 void beamforming_get_ndpa_frame(PADAPTER Adapter, union recv_frame *precv_frame)
\r
262 u8 *pframe = precv_frame->u.hdr.rx_data;
\r
263 struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
\r
264 struct beamforming_entry *pBeamformEntry = NULL;
\r
266 //DBG_871X("beamforming_get_ndpa_frame\n");
\r
268 if(IS_HARDWARE_TYPE_8812(Adapter) == _FALSE)
\r
270 else if(GetFrameSubType(pframe) != WIFI_NDPA)
\r
273 ta = GetAddr2Ptr(pframe);
\r
274 // Remove signaling TA.
\r
275 ta[0] = ta[0] & 0xFE;
\r
277 pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx);
\r
279 if(pBeamformEntry == NULL)
\r
281 else if(!(pBeamformEntry->beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU))
\r
283 else if(pBeamformEntry->LogSuccessCnt > 1)
\r
286 Sequence = (pframe[16]) >> 2;
\r
288 if(pBeamformEntry->LogSeq != Sequence)
\r
290 /* Previous frame doesn't retry when meet new sequence number */
\r
291 if(pBeamformEntry->LogSeq != 0xff && pBeamformEntry->LogRetryCnt == 0)
\r
292 pBeamformEntry->LogSuccessCnt++;
\r
294 pBeamformEntry->LogSeq = Sequence;
\r
295 pBeamformEntry->LogRetryCnt = 0;
\r
299 if(pBeamformEntry->LogRetryCnt == 3)
\r
300 beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_CLK, NULL, 0, 1);
\r
302 pBeamformEntry->LogRetryCnt++;
\r
305 DBG_871X("%s LogSeq %d LogRetryCnt %d LogSuccessCnt %d\n",
\r
306 __FUNCTION__, pBeamformEntry->LogSeq, pBeamformEntry->LogRetryCnt, pBeamformEntry->LogSuccessCnt);
\r
309 BOOLEAN issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
\r
311 struct xmit_frame *pmgntframe;
\r
312 struct pkt_attrib *pattrib;
\r
313 struct rtw_ieee80211_hdr *pwlanhdr;
\r
314 struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv);
\r
315 struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
\r
316 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
\r
317 u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
\r
323 if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL)
\r
329 pattrib = &pmgntframe->attrib;
\r
330 update_mgntframe_attrib(Adapter, pattrib);
\r
332 if (qidx == BCN_QUEUE_INX)
\r
333 pattrib->qsel = QSLT_BEACON;
\r
334 pattrib->rate = MGN_MCS8;
\r
335 pattrib->bwmode = bw;
\r
336 pattrib->order = 1;
\r
337 pattrib->subtype = WIFI_ACTION_NOACK;
\r
339 _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
\r
341 pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
\r
343 pwlanhdr = (struct rtw_ieee80211_hdr*)pframe;
\r
345 fctrl = &pwlanhdr->frame_ctl;
\r
348 SetOrderBit(pframe);
\r
349 SetFrameSubType(pframe, WIFI_ACTION_NOACK);
\r
351 _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
\r
352 _rtw_memcpy(pwlanhdr->addr2, myid(&(Adapter->eeprompriv)), ETH_ALEN);
\r
353 _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
\r
355 if( pmlmeext->cur_wireless_mode == WIRELESS_11B)
\r
360 duration = 2*aSifsTime + 40;
\r
362 if(bw == CHANNEL_WIDTH_40)
\r
367 SetDuration(pframe, duration);
\r
370 SET_HT_CTRL_CSI_STEERING(pframe+24, 3);
\r
371 SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe+24, 1);
\r
373 _rtw_memcpy(pframe+28, ActionHdr, 4);
\r
375 pattrib->pktlen = 32;
\r
377 pattrib->last_txcmdsz = pattrib->pktlen;
\r
379 dump_mgntframe(Adapter, pmgntframe);
\r
384 BOOLEAN beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
\r
386 return issue_ht_ndpa_packet(Adapter, ra, bw, qidx);
\r
389 BOOLEAN issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
\r
391 struct xmit_frame *pmgntframe;
\r
392 struct pkt_attrib *pattrib;
\r
393 struct rtw_ieee80211_hdr *pwlanhdr;
\r
394 struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv);
\r
395 struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
\r
396 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
\r
397 struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
\r
398 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
399 struct rtw_ndpa_sta_info sta_info;
\r
403 u8 sequence = 0, aSifsTime = 0;
\r
405 if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL)
\r
411 pattrib = &pmgntframe->attrib;
\r
412 update_mgntframe_attrib(Adapter, pattrib);
\r
414 if (qidx == BCN_QUEUE_INX)
\r
415 pattrib->qsel = QSLT_BEACON;
\r
416 pattrib->rate = MGN_VHT2SS_MCS0;
\r
417 pattrib->bwmode = bw;
\r
418 pattrib->subtype = WIFI_NDPA;
\r
420 _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
\r
422 pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
\r
424 pwlanhdr = (struct rtw_ieee80211_hdr*)pframe;
\r
426 fctrl = &pwlanhdr->frame_ctl;
\r
429 SetFrameSubType(pframe, WIFI_NDPA);
\r
431 _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
\r
432 _rtw_memcpy(pwlanhdr->addr2, myid(&(Adapter->eeprompriv)), ETH_ALEN);
\r
434 if (IsSupported5G(pmlmeext->cur_wireless_mode) || IsSupportedHT(pmlmeext->cur_wireless_mode))
\r
439 duration = 2*aSifsTime + 44;
\r
441 if(bw == CHANNEL_WIDTH_80)
\r
443 else if(bw == CHANNEL_WIDTH_40)
\r
448 SetDuration(pframe, duration);
\r
450 sequence = pBeamInfo->sounding_sequence<< 2;
\r
451 if (pBeamInfo->sounding_sequence >= 0x3f)
\r
452 pBeamInfo->sounding_sequence = 0;
\r
454 pBeamInfo->sounding_sequence++;
\r
456 _rtw_memcpy(pframe+16, &sequence,1);
\r
458 if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
\r
461 sta_info.aid = aid;
\r
462 sta_info.feedback_type = 0;
\r
463 sta_info.nc_index= 0;
\r
465 _rtw_memcpy(pframe+17, (u8 *)&sta_info, 2);
\r
467 pattrib->pktlen = 19;
\r
469 pattrib->last_txcmdsz = pattrib->pktlen;
\r
471 dump_mgntframe(Adapter, pmgntframe);
\r
476 BOOLEAN beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
\r
478 return issue_vht_ndpa_packet(Adapter, ra, aid, bw, qidx);
\r
481 BOOLEAN beamfomring_bSounding(struct beamforming_info *pBeamInfo)
\r
483 BOOLEAN bSounding = _FALSE;
\r
485 if(( beamforming_get_beamform_cap(pBeamInfo) & BEAMFORMER_CAP) == 0)
\r
486 bSounding = _FALSE;
\r
493 u8 beamforming_sounding_idx(struct beamforming_info *pBeamInfo)
\r
498 for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
\r
500 if (pBeamInfo->beamforming_entry[i].bUsed &&
\r
501 (_FALSE == pBeamInfo->beamforming_entry[i].bSound))
\r
511 SOUNDING_MODE beamforming_sounding_mode(struct beamforming_info *pBeamInfo, u8 idx)
\r
513 struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx];
\r
514 SOUNDING_MODE mode;
\r
516 if(BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU)
\r
518 mode = SOUNDING_FW_VHT_TIMER;
\r
520 else if(BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
\r
522 mode = SOUNDING_FW_HT_TIMER;
\r
526 mode = SOUNDING_STOP_All_TIMER;
\r
532 u16 beamforming_sounding_time(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
\r
534 u16 sounding_time = 0xffff;
\r
535 struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx];
\r
537 sounding_time = BeamEntry.sound_period;
\r
539 return sounding_time;
\r
542 CHANNEL_WIDTH beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
\r
544 CHANNEL_WIDTH sounding_bw = CHANNEL_WIDTH_20;
\r
545 struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx];
\r
547 sounding_bw = BeamEntry.sound_bw;
\r
549 return sounding_bw;
\r
552 BOOLEAN beamforming_select_beam_entry(struct beamforming_info *pBeamInfo)
\r
554 struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info);
\r
556 pSoundInfo->sound_idx = beamforming_sounding_idx(pBeamInfo);
\r
558 if(pSoundInfo->sound_idx < BEAMFORMING_ENTRY_NUM)
\r
559 pSoundInfo->sound_mode = beamforming_sounding_mode(pBeamInfo, pSoundInfo->sound_idx);
\r
561 pSoundInfo->sound_mode = SOUNDING_STOP_All_TIMER;
\r
563 if(SOUNDING_STOP_All_TIMER == pSoundInfo->sound_mode)
\r
569 pSoundInfo->sound_bw = beamforming_sounding_bw(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx );
\r
570 pSoundInfo->sound_period = beamforming_sounding_time(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx );
\r
575 BOOLEAN beamforming_start_fw(PADAPTER adapter, u8 idx)
\r
578 struct beamforming_entry *pEntry;
\r
579 BOOLEAN ret = _TRUE;
\r
580 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
581 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
583 pEntry = &(pBeamInfo->beamforming_entry[idx]);
\r
584 if(pEntry->bUsed == _FALSE)
\r
586 DBG_871X("Skip Beamforming, no entry for Idx =%d\n", idx);
\r
590 pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
\r
591 pEntry->bSound = _TRUE;
\r
592 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx);
\r
597 void beamforming_end_fw(PADAPTER adapter)
\r
601 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx);
\r
603 DBG_871X("%s\n", __FUNCTION__);
\r
606 BOOLEAN beamforming_start_period(PADAPTER adapter)
\r
608 BOOLEAN ret = _TRUE;
\r
609 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
610 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
611 struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info);
\r
613 beamforming_dym_ndpa_rate(adapter);
\r
615 beamforming_select_beam_entry(pBeamInfo);
\r
617 if(pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
\r
619 ret = beamforming_start_fw(adapter, pSoundInfo->sound_idx);
\r
626 DBG_871X("%s Idx %d Mode %d BW %d Period %d\n", __FUNCTION__,
\r
627 pSoundInfo->sound_idx, pSoundInfo->sound_mode, pSoundInfo->sound_bw, pSoundInfo->sound_period);
\r
632 void beamforming_end_period(PADAPTER adapter)
\r
635 struct beamforming_entry *pBeamformEntry;
\r
636 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
637 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
638 struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info);
\r
641 if(pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
\r
643 beamforming_end_fw(adapter);
\r
647 void beamforming_notify(PADAPTER adapter)
\r
649 BOOLEAN bSounding = _FALSE;
\r
650 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(&(adapter->mlmepriv));
\r
652 bSounding = beamfomring_bSounding(pBeamInfo);
\r
654 if(pBeamInfo->beamforming_state == BEAMFORMING_STATE_IDLE)
\r
658 if(beamforming_start_period(adapter) == _TRUE)
\r
659 pBeamInfo->beamforming_state = BEAMFORMING_STATE_START;
\r
662 else if(pBeamInfo->beamforming_state == BEAMFORMING_STATE_START)
\r
666 if(beamforming_start_period(adapter) == _FALSE)
\r
667 pBeamInfo->beamforming_state = BEAMFORMING_STATE_END;
\r
671 beamforming_end_period(adapter);
\r
672 pBeamInfo->beamforming_state = BEAMFORMING_STATE_END;
\r
675 else if(pBeamInfo->beamforming_state == BEAMFORMING_STATE_END)
\r
679 if(beamforming_start_period(adapter) == _TRUE)
\r
680 pBeamInfo->beamforming_state = BEAMFORMING_STATE_START;
\r
685 DBG_871X("%s BeamformState %d\n", __FUNCTION__, pBeamInfo->beamforming_state);
\r
688 DBG_871X("%s BeamformState %d bSounding %d\n", __FUNCTION__, pBeamInfo->beamforming_state, bSounding);
\r
691 BOOLEAN beamforming_init_entry(PADAPTER adapter, struct sta_info *psta, u8* idx)
\r
693 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
694 struct ht_priv *phtpriv = &(pmlmepriv->htpriv);
\r
695 #ifdef CONFIG_80211AC_VHT
\r
696 struct vht_priv *pvhtpriv = &(pmlmepriv->vhtpriv);
\r
698 struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
\r
699 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
\r
700 struct beamforming_entry *pBeamformEntry = NULL;
\r
704 CHANNEL_WIDTH bw = CHANNEL_WIDTH_20;
\r
705 BEAMFORMING_CAP beamform_cap = BEAMFORMING_CAP_NONE;
\r
707 // The current setting does not support Beaforming
\r
708 if (0 == phtpriv->beamform_cap
\r
709 #ifdef CONFIG_80211AC_VHT
\r
710 && 0 == pvhtpriv->beamform_cap
\r
713 DBG_871X("The configuration disabled Beamforming! Skip...\n");
\r
719 mac_id = psta->mac_id;
\r
720 wireless_mode = psta->wireless_mode;
\r
721 bw = psta->bw_mode;
\r
723 if (IsSupportedHT(wireless_mode) || IsSupportedVHT(wireless_mode)) {
\r
727 cur_beamform = psta->htpriv.beamform_cap;
\r
729 // We are Beamformee because the STA is Beamformer
\r
730 if(TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE))
\r
731 beamform_cap =(BEAMFORMING_CAP)(beamform_cap |BEAMFORMEE_CAP_HT_EXPLICIT);
\r
733 // We are Beamformer because the STA is Beamformee
\r
734 if(TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE))
\r
735 beamform_cap =(BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT);
\r
736 #ifdef CONFIG_80211AC_VHT
\r
737 if (IsSupportedVHT(wireless_mode)) {
\r
739 cur_beamform = psta->vhtpriv.beamform_cap;
\r
741 // We are Beamformee because the STA is Beamformer
\r
742 if(TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMER_ENABLE))
\r
743 beamform_cap =(BEAMFORMING_CAP)(beamform_cap |BEAMFORMEE_CAP_VHT_SU);
\r
744 // We are Beamformer because the STA is Beamformee
\r
745 if(TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))
\r
746 beamform_cap =(BEAMFORMING_CAP)(beamform_cap |BEAMFORMER_CAP_VHT_SU);
\r
748 #endif //CONFIG_80211AC_VHT
\r
750 if(beamform_cap == BEAMFORMING_CAP_NONE)
\r
753 DBG_871X("Beamforming Config Capability = 0x%02X\n", beamform_cap);
\r
755 pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx);
\r
756 if (pBeamformEntry == NULL) {
\r
757 pBeamformEntry = beamforming_add_entry(adapter, ra, aid, mac_id, bw, beamform_cap, idx);
\r
758 if(pBeamformEntry == NULL)
\r
761 pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
\r
763 // Entry has been created. If entry is initialing or progressing then errors occur.
\r
764 if (pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED &&
\r
765 pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
\r
766 DBG_871X("Error State of Beamforming");
\r
769 pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
\r
773 pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
\r
775 DBG_871X("%s Idx %d\n", __FUNCTION__, *idx);
\r
783 void beamforming_deinit_entry(PADAPTER adapter, u8* ra)
\r
786 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
788 if(beamforming_remove_entry(pmlmepriv, ra, &idx) == _TRUE)
\r
790 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx);
\r
793 DBG_871X("%s Idx %d\n", __FUNCTION__, idx);
\r
796 void beamforming_reset(PADAPTER adapter)
\r
799 struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
\r
800 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
802 for(idx = 0; idx < BEAMFORMING_ENTRY_NUM; idx++)
\r
804 if(pBeamInfo->beamforming_entry[idx].bUsed == _TRUE)
\r
806 pBeamInfo->beamforming_entry[idx].bUsed = _FALSE;
\r
807 pBeamInfo->beamforming_entry[idx].beamforming_entry_cap = BEAMFORMING_CAP_NONE;
\r
808 pBeamInfo->beamforming_entry[idx].beamforming_entry_state= BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
\r
809 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx);
\r
813 DBG_871X("%s\n", __FUNCTION__);
\r
816 void beamforming_sounding_fail(PADAPTER Adapter)
\r
818 struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
\r
819 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
820 struct beamforming_entry *pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]);
\r
822 pEntry->bSound = _FALSE;
\r
823 rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx);
\r
824 beamforming_deinit_entry(Adapter, pEntry->mac_addr);
\r
827 void beamforming_check_sounding_success(PADAPTER Adapter,BOOLEAN status)
\r
829 struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
\r
830 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
\r
831 struct beamforming_entry *pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]);
\r
835 pEntry->LogStatusFailCnt = 0;
\r
839 pEntry->LogStatusFailCnt++;
\r
840 DBG_871X("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt);
\r
842 if(pEntry->LogStatusFailCnt > 20)
\r
844 DBG_871X("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __FUNCTION__);
\r
845 //pEntry->bSound = _FALSE;
\r
846 //rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx);
\r
847 //beamforming_deinit_entry(Adapter, pEntry->mac_addr);
\r
848 beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_FAIL, NULL, 0, 1);
\r
852 void beamforming_enter(PADAPTER adapter, PVOID psta)
\r
856 if(beamforming_init_entry(adapter, (struct sta_info *)psta, &idx))
\r
857 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8 *)&idx);
\r
859 //DBG_871X("%s Idx %d\n", __FUNCTION__, idx);
\r
862 void beamforming_leave(PADAPTER adapter,u8* ra)
\r
865 beamforming_reset(adapter);
\r
867 beamforming_deinit_entry(adapter, ra);
\r
869 beamforming_notify(adapter);
\r
872 BEAMFORMING_CAP beamforming_get_beamform_cap(struct beamforming_info *pBeamInfo)
\r
875 BOOLEAN bSelfBeamformer = _FALSE;
\r
876 BOOLEAN bSelfBeamformee = _FALSE;
\r
877 struct beamforming_entry beamforming_entry;
\r
878 BEAMFORMING_CAP beamform_cap = BEAMFORMING_CAP_NONE;
\r
880 for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
\r
882 beamforming_entry = pBeamInfo->beamforming_entry[i];
\r
884 if(beamforming_entry.bUsed)
\r
886 if( (beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU) ||
\r
887 (beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_HT_EXPLICIT))
\r
888 bSelfBeamformee = _TRUE;
\r
889 if( (beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) ||
\r
890 (beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT))
\r
891 bSelfBeamformer = _TRUE;
\r
894 if(bSelfBeamformer && bSelfBeamformee)
\r
895 i = BEAMFORMING_ENTRY_NUM;
\r
898 if(bSelfBeamformer)
\r
899 beamform_cap |= BEAMFORMER_CAP;
\r
900 if(bSelfBeamformee)
\r
901 beamform_cap |= BEAMFORMEE_CAP;
\r
903 return beamform_cap;
\r
906 void beamforming_watchdog(PADAPTER Adapter)
\r
908 struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(( &(Adapter->mlmepriv)));
\r
910 if(pBeamInfo->beamforming_state != BEAMFORMING_STATE_START)
\r
913 beamforming_dym_period(Adapter);
\r
914 beamforming_dym_ndpa_rate(Adapter);
\r
917 void beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf)
\r
924 case BEAMFORMING_CTRL_ENTER:
\r
925 beamforming_enter(padapter, (PVOID)pbuf);
\r
928 case BEAMFORMING_CTRL_LEAVE:
\r
929 beamforming_leave(padapter, pbuf);
\r
932 case BEAMFORMING_CTRL_SOUNDING_FAIL:
\r
933 beamforming_sounding_fail(padapter);
\r
936 case BEAMFORMING_CTRL_SOUNDING_CLK:
\r
937 rtw_hal_set_hwreg(padapter, HW_VAR_SOUNDING_CLK, NULL);
\r
947 u8 beamforming_wk_cmd(_adapter*padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)
\r
949 struct cmd_obj *ph2c;
\r
950 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
\r
951 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
\r
960 ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
\r
966 pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
\r
967 if(pdrvextra_cmd_parm==NULL){
\r
968 rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
\r
973 if (pbuf != NULL) {
\r
974 wk_buf = rtw_zmalloc(size);
\r
976 rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
\r
977 rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
\r
982 _rtw_memcpy(wk_buf, pbuf, size);
\r
988 pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;
\r
989 pdrvextra_cmd_parm->type = type;
\r
990 pdrvextra_cmd_parm->size = size;
\r
991 pdrvextra_cmd_parm->pbuf = wk_buf;
\r
993 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
\r
995 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
\r
999 beamforming_wk_hdl(padapter, type, pbuf);
\r
1009 #endif //CONFIG_BEAMFORMING
\r