Path: blob/master/ALFA-W1F1/RTL8814AU/core/rtw_beamforming.c
1307 views
/******************************************************************************1*2* Copyright(c) 2007 - 2017 Realtek Corporation.3*4* This program is free software; you can redistribute it and/or modify it5* under the terms of version 2 of the GNU General Public License as6* published by the Free Software Foundation.7*8* This program is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for11* more details.12*13*****************************************************************************/14#define _RTW_BEAMFORMING_C_1516#include <drv_types.h>17#include <hal_data.h>1819#ifdef CONFIG_BEAMFORMING2021#ifdef RTW_BEAMFORMING_VERSION_22223struct ndpa_sta_info {24u16 aid:12;25u16 feedback_type:1;26u16 nc_index:3;27};2829static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *g_id, u16 *p_aid)30{31struct mlme_priv *mlme;32u16 aid;33u8 *bssid;34u16 val16;35u8 i;363738mlme = &adapter->mlmepriv;3940if (check_fwstate(mlme, WIFI_AP_STATE)) {41/*42* Sent by an AP and addressed to a STA associated with that AP43* or sent by a DLS or TDLS STA in a direct path to44* a DLS or TDLS peer STA45*/4647aid = sta->cmn.aid;48bssid = adapter_mac_addr(adapter);49RTW_INFO("%s: AID=0x%x BSSID=" MAC_FMT "\n",50__FUNCTION__, sta->cmn.aid, MAC_ARG(bssid));5152/* AID[0:8] */53aid &= 0x1FF;54/* BSSID[44:47] xor BSSID[40:43] */55val16 = ((bssid[5] & 0xF0) >> 4) ^ (bssid[5] & 0xF);56/* (dec(AID[0:8]) + dec(BSSID)*2^5) mod 2^9 */57*p_aid = (aid + (val16 << 5)) & 0x1FF;58*g_id = 63;59} else if ((check_fwstate(mlme, WIFI_ADHOC_STATE) == _TRUE)60|| (check_fwstate(mlme, WIFI_ADHOC_MASTER_STATE) == _TRUE)) {61/*62* Otherwise, includes63* 1. Sent to an IBSS STA64* 2. Sent by an AP to a non associated STA65* 3. Sent to a STA for which it is not known66* which condition is applicable67*/68*p_aid = 0;69*g_id = 63;70} else {71/* Addressed to AP */72bssid = sta->cmn.mac_addr;73RTW_INFO("%s: BSSID=" MAC_FMT "\n", __FUNCTION__, MAC_ARG(bssid));7475/* BSSID[39:47] */76*p_aid = (bssid[5] << 1) | (bssid[4] >> 7);77*g_id = 0;78}7980RTW_INFO("%s: GROUP_ID=0x%02x PARTIAL_AID=0x%04x\n",81__FUNCTION__, *g_id, *p_aid);82}8384/*85* Parameters86* adapter struct _adapter*87* sta struct sta_info*88* sta_bf_cap beamforming capabe of sta89* sounding_dim Number of Sounding Dimensions90* comp_steering Compressed Steering Number of Beamformer Antennas Supported91*/92static void _get_sta_beamform_cap(PADAPTER adapter, struct sta_info *sta,93u8 *sta_bf_cap, u8 *sounding_dim, u8 *comp_steering)94{95struct beamforming_info *info;96struct ht_priv *ht;97#ifdef CONFIG_80211AC_VHT98struct vht_priv *vht;99#endif /* CONFIG_80211AC_VHT */100u16 bf_cap;101102103*sta_bf_cap = 0;104*sounding_dim = 0;105*comp_steering = 0;106107info = GET_BEAMFORM_INFO(adapter);108ht = &adapter->mlmepriv.htpriv;109#ifdef CONFIG_80211AC_VHT110vht = &adapter->mlmepriv.vhtpriv;111#endif /* CONFIG_80211AC_VHT */112113if (is_supported_ht(sta->wireless_mode) == _TRUE) {114/* HT */115bf_cap = ht->beamform_cap;116117if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {118info->beamforming_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;119*sta_bf_cap |= BEAMFORMER_CAP_HT_EXPLICIT;120*sounding_dim = (bf_cap & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6;121}122if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {123info->beamforming_cap |= BEAMFORMER_CAP_HT_EXPLICIT;124*sta_bf_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;125*comp_steering = (bf_cap & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4;126}127}128129#ifdef CONFIG_80211AC_VHT130if (is_supported_vht(sta->wireless_mode) == _TRUE) {131/* VHT */132bf_cap = vht->beamform_cap;133134/* We are SU Beamformee because the STA is SU Beamformer */135if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) {136info->beamforming_cap |= BEAMFORMEE_CAP_VHT_SU;137*sta_bf_cap |= BEAMFORMER_CAP_VHT_SU;138139/* We are MU Beamformee because the STA is MU Beamformer */140if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) {141info->beamforming_cap |= BEAMFORMEE_CAP_VHT_MU;142*sta_bf_cap |= BEAMFORMER_CAP_VHT_MU;143}144145*sounding_dim = (bf_cap & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;146}147/* We are SU Beamformer because the STA is SU Beamformee */148if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {149info->beamforming_cap |= BEAMFORMER_CAP_VHT_SU;150*sta_bf_cap |= BEAMFORMEE_CAP_VHT_SU;151152/* We are MU Beamformer because the STA is MU Beamformee */153if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {154info->beamforming_cap |= BEAMFORMER_CAP_VHT_MU;155*sta_bf_cap |= BEAMFORMEE_CAP_VHT_MU;156}157158*comp_steering = (bf_cap & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;159}160}161#endif /* CONFIG_80211AC_VHT */162}163164static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, enum channel_width bw)165{166/* General */167struct xmit_priv *pxmitpriv;168struct mlme_ext_priv *pmlmeext;169struct mlme_ext_info *pmlmeinfo;170struct xmit_frame *pmgntframe;171/* Beamforming */172struct beamforming_info *info;173struct beamformee_entry *bfee;174struct ndpa_sta_info sta_info;175u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xE0, 0x4C};176/* MISC */177struct pkt_attrib *attrib;178struct rtw_ieee80211_hdr *pwlanhdr;179enum MGN_RATE txrate;180u8 *pframe;181u16 duration = 0;182u8 aSifsTime = 0;183184185RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));186187pxmitpriv = &adapter->xmitpriv;188pmlmeext = &adapter->mlmeextpriv;189pmlmeinfo = &pmlmeext->mlmext_info;190bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra);191if (!bfee) {192RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__);193return _FALSE;194}195196pmgntframe = alloc_mgtxmitframe(pxmitpriv);197if (!pmgntframe) {198RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);199return _FALSE;200}201202txrate = beamforming_get_htndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer);203204/* update attribute */205attrib = &pmgntframe->attrib;206update_mgntframe_attrib(adapter, attrib);207/*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */208attrib->subtype = WIFI_ACTION_NOACK;209attrib->bwmode = bw;210/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */211attrib->order = 1;212attrib->rate = (u8)txrate;213attrib->bf_pkt_type = 0;214215_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);216pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;217pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;218219/* Frame control */220pwlanhdr->frame_ctl = 0;221set_frame_sub_type(pframe, attrib->subtype);222set_order_bit(pframe);223224/* Duration */225if (pmlmeext->cur_wireless_mode == WIRELESS_11B)226aSifsTime = 10;227else228aSifsTime = 16;229duration = 2 * aSifsTime + 40;230if (bw == CHANNEL_WIDTH_40)231duration += 87;232else233duration += 180;234set_duration(pframe, duration);235236/* DA */237_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);238/* SA */239_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);240/* BSSID */241_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);242243/* HT control field */244SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);245SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);246247/*248* Frame Body249* Category field: vender-specific value, 0x7F250* OUI: 0x00E04C251*/252_rtw_memcpy(pframe + 28, ActionHdr, 4);253254attrib->pktlen = 32;255attrib->last_txcmdsz = attrib->pktlen;256257dump_mgntframe(adapter, pmgntframe);258259return _TRUE;260}261262static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, enum channel_width bw)263{264/* General */265struct xmit_priv *pxmitpriv;266struct mlme_ext_priv *pmlmeext;267struct xmit_frame *pmgntframe;268/* Beamforming */269struct beamforming_info *info;270struct beamformee_entry *bfee;271struct ndpa_sta_info sta_info;272/* MISC */273struct pkt_attrib *attrib;274struct rtw_ieee80211_hdr *pwlanhdr;275u8 *pframe;276enum MGN_RATE txrate;277u16 duration = 0;278u8 sequence = 0, aSifsTime = 0;279280281RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));282283pxmitpriv = &adapter->xmitpriv;284pmlmeext = &adapter->mlmeextpriv;285info = GET_BEAMFORM_INFO(adapter);286bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra);287if (!bfee) {288RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__);289return _FALSE;290}291292pmgntframe = alloc_mgtxmitframe(pxmitpriv);293if (!pmgntframe) {294RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);295return _FALSE;296}297298txrate = beamforming_get_vht_ndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer);299300/* update attribute */301attrib = &pmgntframe->attrib;302update_mgntframe_attrib(adapter, attrib);303/*pattrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */304attrib->subtype = WIFI_NDPA;305attrib->bwmode = bw;306/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */307attrib->rate = (u8)txrate;308attrib->bf_pkt_type = 0;309310_rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);311pframe = pmgntframe->buf_addr + TXDESC_OFFSET;312pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;313314/* Frame control */315pwlanhdr->frame_ctl = 0;316set_frame_sub_type(pframe, attrib->subtype);317318/* Duration */319if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))320aSifsTime = 16;321else322aSifsTime = 10;323duration = 2 * aSifsTime + 44;324if (bw == CHANNEL_WIDTH_80)325duration += 40;326else if (bw == CHANNEL_WIDTH_40)327duration += 87;328else329duration += 180;330set_duration(pframe, duration);331332/* RA */333_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);334335/* TA */336_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);337338/* Sounding Sequence, bit0~1 is reserved */339sequence = info->sounding_sequence << 2;340if (info->sounding_sequence >= 0x3f)341info->sounding_sequence = 0;342else343info->sounding_sequence++;344_rtw_memcpy(pframe + 16, &sequence, 1);345346/* STA Info */347/*348* "AID12" Equal to 0 if the STA is an AP, mesh STA or349* STA that is a member of an IBSS350*/351if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _FALSE)352aid = 0;353sta_info.aid = aid;354/* "Feedback Type" set to 0 for SU */355sta_info.feedback_type = 0;356/* "Nc Index" reserved if the Feedback Type field indicates SU */357sta_info.nc_index = 0;358_rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2);359360attrib->pktlen = 19;361attrib->last_txcmdsz = attrib->pktlen;362363dump_mgntframe(adapter, pmgntframe);364365return _TRUE;366}367368static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, enum channel_width bw)369{370/* General */371struct xmit_priv *pxmitpriv;372struct mlme_ext_priv *pmlmeext;373struct xmit_frame *pmgntframe;374/* Beamforming */375struct beamforming_info *info;376struct sounding_info *sounding;377struct beamformee_entry *bfee;378struct ndpa_sta_info sta_info;379/* MISC */380struct pkt_attrib *attrib;381struct rtw_ieee80211_hdr *pwlanhdr;382enum MGN_RATE txrate;383u8 *pframe;384u8 *ra = NULL;385u16 duration = 0;386u8 sequence = 0, aSifsTime = 0;387u8 i;388389390RTW_INFO("+%s\n", __FUNCTION__);391392pxmitpriv = &adapter->xmitpriv;393pmlmeext = &adapter->mlmeextpriv;394info = GET_BEAMFORM_INFO(adapter);395sounding = &info->sounding_info;396397txrate = MGN_VHT2SS_MCS0;398399/*400* Fill the first MU BFee entry (STA1) MAC addr to destination address then401* HW will change A1 to broadcast addr.402* 2015.05.28. Suggested by SD1 Chunchu.403*/404bfee = &info->bfee_entry[sounding->mu_sounding_list[0]];405ra = bfee->mac_addr;406407pmgntframe = alloc_mgtxmitframe(pxmitpriv);408if (!pmgntframe) {409RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);410return _FALSE;411}412413/* update attribute */414attrib = &pmgntframe->attrib;415update_mgntframe_attrib(adapter, attrib);416/*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */417attrib->subtype = WIFI_NDPA;418attrib->bwmode = bw;419/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */420attrib->rate = (u8)txrate;421/* Set TxBFPktType of Tx desc to unicast type if there is only one MU STA for HW design */422if (info->sounding_info.candidate_mu_bfee_cnt > 1)423attrib->bf_pkt_type = 1;424else425attrib->bf_pkt_type = 0;426427_rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);428pframe = pmgntframe->buf_addr + TXDESC_OFFSET;429pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;430431/* Frame control */432pwlanhdr->frame_ctl = 0;433set_frame_sub_type(pframe, attrib->subtype);434435/* Duration */436if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))437aSifsTime = 16;438else439aSifsTime = 10;440duration = 2 * aSifsTime + 44;441if (bw == CHANNEL_WIDTH_80)442duration += 40;443else if (bw == CHANNEL_WIDTH_40)444duration += 87;445else446duration += 180;447set_duration(pframe, duration);448449/* RA */450_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);451452/* TA */453_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);454455/* Sounding Sequence, bit0~1 is reserved */456sequence = info->sounding_sequence << 2;457if (info->sounding_sequence >= 0x3f)458info->sounding_sequence = 0;459else460info->sounding_sequence++;461_rtw_memcpy(pframe + 16, &sequence, 1);462463attrib->pktlen = 17;464465/*466* Construct STA info. for multiple STAs467* STA Info1, ..., STA Info n468*/469for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) {470bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];471sta_info.aid = bfee->aid;472sta_info.feedback_type = 1; /* 1'b1: MU */473sta_info.nc_index = 0;474_rtw_memcpy(pframe + attrib->pktlen, (u8 *)&sta_info, 2);475attrib->pktlen += 2;476}477478attrib->last_txcmdsz = attrib->pktlen;479480dump_mgntframe(adapter, pmgntframe);481482return _TRUE;483}484485static u8 _send_bf_report_poll(PADAPTER adapter, u8 *ra, u8 bFinalPoll)486{487/* General */488struct xmit_priv *pxmitpriv;489struct xmit_frame *pmgntframe;490/* MISC */491struct pkt_attrib *attrib;492struct rtw_ieee80211_hdr *pwlanhdr;493u8 *pframe;494495496RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));497498pxmitpriv = &adapter->xmitpriv;499500pmgntframe = alloc_mgtxmitframe(pxmitpriv);501if (!pmgntframe) {502RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);503return _FALSE;504}505506/* update attribute */507attrib = &pmgntframe->attrib;508update_mgntframe_attrib(adapter, attrib);509/*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */510attrib->subtype = WIFI_BF_REPORT_POLL;511attrib->bwmode = CHANNEL_WIDTH_20;512/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */513attrib->rate = MGN_6M;514if (bFinalPoll)515attrib->bf_pkt_type = 3;516else517attrib->bf_pkt_type = 2;518519_rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);520pframe = pmgntframe->buf_addr + TXDESC_OFFSET;521pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;522523/* Frame control */524pwlanhdr->frame_ctl = 0;525set_frame_sub_type(pframe, attrib->subtype);526527/* Duration */528set_duration(pframe, 100);529530/* RA */531_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);532533/* TA */534_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);535536/* Feedback Segment Retransmission Bitmap */537pframe[16] = 0xFF;538539attrib->pktlen = 17;540attrib->last_txcmdsz = attrib->pktlen;541542dump_mgntframe(adapter, pmgntframe);543544return _TRUE;545}546547static void _sounding_update_min_period(PADAPTER adapter, u16 period, u8 leave)548{549struct beamforming_info *info;550struct beamformee_entry *bfee;551u8 i = 0;552u16 min_val = 0xFFFF;553554555info = GET_BEAMFORM_INFO(adapter);556557if (_TRUE == leave) {558/*559* When a BFee left,560* we need to find the latest min sounding period561* from the remaining BFees562*/563for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {564bfee = &info->bfee_entry[i];565if ((bfee->used == _TRUE)566&& (bfee->sound_period < min_val))567min_val = bfee->sound_period;568}569570if (min_val == 0xFFFF)571info->sounding_info.min_sounding_period = 0;572else573info->sounding_info.min_sounding_period = min_val;574} else {575if ((info->sounding_info.min_sounding_period == 0)576|| (period < info->sounding_info.min_sounding_period))577info->sounding_info.min_sounding_period = period;578}579}580581static void _sounding_init(struct sounding_info *sounding)582{583_rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU);584_rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU);585sounding->state = SOUNDING_STATE_NONE;586sounding->su_bfee_curidx = 0xFF;587sounding->candidate_mu_bfee_cnt = 0;588sounding->min_sounding_period = 0;589sounding->sound_remain_cnt_per_period = 0;590}591592static void _sounding_reset_vars(PADAPTER adapter)593{594struct beamforming_info *info;595struct sounding_info *sounding;596u8 idx;597598599info = GET_BEAMFORM_INFO(adapter);600sounding = &info->sounding_info;601602_rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU);603_rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU);604sounding->su_bfee_curidx = 0xFF;605sounding->candidate_mu_bfee_cnt = 0;606607/* Clear bSound flag for the new period */608for (idx = 0; idx < MAX_BEAMFORMEE_ENTRY_NUM; idx++) {609if ((info->bfee_entry[idx].used == _TRUE)610&& (info->bfee_entry[idx].sounding == _TRUE)) {611info->bfee_entry[idx].sounding = _FALSE;612info->bfee_entry[idx].bCandidateSoundingPeer = _FALSE;613}614}615}616617/*618* Return619* 0 Prepare sounding list OK620* -1 Fail to prepare sounding list, because no beamformee need to souding621* -2 Fail to prepare sounding list, because beamformee state not ready622*623*/624static int _sounding_get_list(PADAPTER adapter)625{626struct beamforming_info *info;627struct sounding_info *sounding;628struct beamformee_entry *bfee;629u8 i, mu_idx = 0, su_idx = 0, not_ready = 0;630int ret = 0;631632633info = GET_BEAMFORM_INFO(adapter);634sounding = &info->sounding_info;635636/* Add MU BFee list first because MU priority is higher than SU */637for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {638bfee = &info->bfee_entry[i];639if (bfee->used == _FALSE)640continue;641642if (bfee->state != BEAMFORM_ENTRY_HW_STATE_ADDED) {643RTW_ERR("%s: Invalid BFee idx(%d) Hw state=%d\n", __FUNCTION__, i, bfee->state);644not_ready++;645continue;646}647648/*649* Decrease BFee's SoundCnt per period650* If the remain count is 0,651* then it can be sounded at this time652*/653if (bfee->SoundCnt) {654bfee->SoundCnt--;655if (bfee->SoundCnt)656continue;657}658659/*660* <tynli_Note>661* If the STA supports MU BFee capability then we add it to MUSoundingList directly662* because we can only sound one STA by unicast NDPA with MU cap enabled to get correct channel info.663* Suggested by BB team Luke Lee. 2015.11.25.664*/665if (bfee->cap & BEAMFORMEE_CAP_VHT_MU) {666/* MU BFee */667if (mu_idx >= MAX_NUM_BEAMFORMEE_MU) {668RTW_ERR("%s: Too much MU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_MU);669continue;670}671672if (bfee->bApplySounding == _TRUE) {673bfee->bCandidateSoundingPeer = _TRUE;674bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period);675sounding->mu_sounding_list[mu_idx] = i;676mu_idx++;677}678} else if (bfee->cap & (BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {679/* SU BFee (HT/VHT) */680if (su_idx >= MAX_NUM_BEAMFORMEE_SU) {681RTW_ERR("%s: Too much SU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_SU);682continue;683}684685if (bfee->bDeleteSounding == _TRUE) {686sounding->su_sounding_list[su_idx] = i;687su_idx++;688} else if ((bfee->bApplySounding == _TRUE)689&& (bfee->bSuspendSUCap == _FALSE)) {690bfee->bCandidateSoundingPeer = _TRUE;691bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period);692sounding->su_sounding_list[su_idx] = i;693su_idx++;694}695}696}697698sounding->candidate_mu_bfee_cnt = mu_idx;699700if (su_idx + mu_idx == 0) {701ret = -1;702if (not_ready)703ret = -2;704}705706RTW_INFO("-%s: There are %d SU and %d MU BFees in this sounding period\n", __FUNCTION__, su_idx, mu_idx);707708return ret;709}710711static void _sounding_handler(PADAPTER adapter)712{713struct beamforming_info *info;714struct sounding_info *sounding;715struct beamformee_entry *bfee;716u8 su_idx, i;717u32 timeout_period = 0;718u8 set_timer = _FALSE;719int ret = 0;720static u16 wait_cnt = 0;721722723info = GET_BEAMFORM_INFO(adapter);724sounding = &info->sounding_info;725726RTW_DBG("+%s: state=%d\n", __FUNCTION__, sounding->state);727if ((sounding->state != SOUNDING_STATE_INIT)728&& (sounding->state != SOUNDING_STATE_SU_SOUNDDOWN)729&& (sounding->state != SOUNDING_STATE_MU_SOUNDDOWN)730&& (sounding->state != SOUNDING_STATE_SOUNDING_TIMEOUT)) {731RTW_WARN("%s: Invalid State(%d) and return!\n", __FUNCTION__, sounding->state);732return;733}734735if (sounding->state == SOUNDING_STATE_INIT) {736RTW_INFO("%s: Sounding start\n", __FUNCTION__);737738/* Init Var */739_sounding_reset_vars(adapter);740741/* Get the sounding list of this sounding period */742ret = _sounding_get_list(adapter);743if (ret == -1) {744wait_cnt = 0;745sounding->state = SOUNDING_STATE_NONE;746RTW_ERR("%s: No BFees found, set to SOUNDING_STATE_NONE\n", __FUNCTION__);747info->sounding_running--;748return;749}750if (ret == -2) {751RTW_WARN("%s: Temporarily cann't find BFee to sounding\n", __FUNCTION__);752if (wait_cnt < 5) {753wait_cnt++;754} else {755wait_cnt = 0;756sounding->state = SOUNDING_STATE_NONE;757RTW_ERR("%s: Wait changing state timeout!! Set to SOUNDING_STATE_NONE\n", __FUNCTION__);758}759info->sounding_running--;760return;761}762if (ret != 0) {763wait_cnt = 0;764RTW_ERR("%s: Unkown state(%d)!\n", __FUNCTION__, ret);765info->sounding_running--;766return;767768}769770wait_cnt = 0;771772if (check_fwstate(&adapter->mlmepriv, WIFI_SITE_MONITOR) == _TRUE) {773RTW_INFO("%s: Sounding abort! scanning APs...\n", __FUNCTION__);774info->sounding_running--;775return;776}777778rtw_ps_deny(adapter, PS_DENY_BEAMFORMING);779LeaveAllPowerSaveModeDirect(adapter);780}781782/* Get non-sound SU BFee index */783for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) {784su_idx = sounding->su_sounding_list[i];785if (su_idx >= MAX_BEAMFORMEE_ENTRY_NUM)786continue;787bfee = &info->bfee_entry[su_idx];788if (_FALSE == bfee->sounding)789break;790}791if (i < MAX_NUM_BEAMFORMEE_SU) {792sounding->su_bfee_curidx = su_idx;793/* Set to sounding start state */794sounding->state = SOUNDING_STATE_SU_START;795RTW_DBG("%s: Set to SOUNDING_STATE_SU_START\n", __FUNCTION__);796797bfee->sounding = _TRUE;798/* Reset sounding timeout flag for the new sounding */799bfee->bSoundingTimeout = _FALSE;800801if (_TRUE == bfee->bDeleteSounding) {802u8 res = _FALSE;803rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 0);804return;805}806807/* Start SU sounding */808if (bfee->cap & BEAMFORMEE_CAP_VHT_SU)809_send_vht_ndpa_packet(adapter, bfee->mac_addr, bfee->aid, bfee->sound_bw);810else if (bfee->cap & BEAMFORMEE_CAP_HT_EXPLICIT)811_send_ht_ndpa_packet(adapter, bfee->mac_addr, bfee->sound_bw);812813/* Set sounding timeout timer */814_set_timer(&info->sounding_timeout_timer, SU_SOUNDING_TIMEOUT);815return;816}817818if (sounding->candidate_mu_bfee_cnt > 0) {819/*820* If there is no SU BFee then find MU BFee and perform MU sounding821*822* <tynli_note> Need to check the MU starting condition. 2015.12.15.823*/824sounding->state = SOUNDING_STATE_MU_START;825RTW_DBG("%s: Set to SOUNDING_STATE_MU_START\n", __FUNCTION__);826827/* Update MU BFee info */828for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) {829bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];830bfee->sounding = _TRUE;831}832833/* Send MU NDPA */834bfee = &info->bfee_entry[sounding->mu_sounding_list[0]];835_send_vht_mu_ndpa_packet(adapter, bfee->sound_bw);836837/* Send BF report poll if more than 1 MU STA */838for (i = 1; i < sounding->candidate_mu_bfee_cnt; i++) {839bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];840841if (i == (sounding->candidate_mu_bfee_cnt - 1))/* The last STA*/842_send_bf_report_poll(adapter, bfee->mac_addr, _TRUE);843else844_send_bf_report_poll(adapter, bfee->mac_addr, _FALSE);845}846847sounding->candidate_mu_bfee_cnt = 0;848849/* Set sounding timeout timer */850_set_timer(&info->sounding_timeout_timer, MU_SOUNDING_TIMEOUT);851return;852}853854info->sounding_running--;855sounding->state = SOUNDING_STATE_INIT;856RTW_INFO("%s: Sounding finished!\n", __FUNCTION__);857rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING);858}859860static void _sounding_force_stop(PADAPTER adapter)861{862struct beamforming_info *info;863struct sounding_info *sounding;864865info = GET_BEAMFORM_INFO(adapter);866sounding = &info->sounding_info;867868if ((sounding->state == SOUNDING_STATE_SU_START)869|| (sounding->state == SOUNDING_STATE_MU_START)) {870u8 res = _FALSE;871_cancel_timer_ex(&info->sounding_timeout_timer);872rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1);873return;874}875876info->sounding_running--;877sounding->state = SOUNDING_STATE_INIT;878RTW_INFO("%s: Sounding finished!\n", __FUNCTION__);879rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING);880}881882static void _sounding_timer_handler(void *FunctionContext)883{884PADAPTER adapter;885struct beamforming_info *info;886struct sounding_info *sounding;887static u8 delay = 0;888889890RTW_DBG("+%s\n", __FUNCTION__);891892adapter = (PADAPTER)FunctionContext;893info = GET_BEAMFORM_INFO(adapter);894sounding = &info->sounding_info;895896if (SOUNDING_STATE_NONE == sounding->state) {897RTW_INFO("%s: Stop!\n", __FUNCTION__);898if (info->sounding_running)899RTW_WARN("%s: souding_running=%d when thread stop!\n",900__FUNCTION__, info->sounding_running);901return;902}903904_set_timer(&info->sounding_timer, sounding->min_sounding_period);905906if (!info->sounding_running) {907if (SOUNDING_STATE_INIT != sounding->state) {908RTW_WARN("%s: state(%d) != SOUNDING_STATE_INIT!!\n", __FUNCTION__, sounding->state);909sounding->state = SOUNDING_STATE_INIT;910}911delay = 0;912info->sounding_running++;913rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1);914} else {915if (delay != 0xFF)916delay++;917RTW_WARN("%s: souding is still processing...(state:%d, running:%d, delay:%d)\n",918__FUNCTION__, sounding->state, info->sounding_running, delay);919if (delay > 3) {920RTW_WARN("%s: Stop sounding!!\n", __FUNCTION__);921_sounding_force_stop(adapter);922}923}924}925926static void _sounding_timeout_timer_handler(void *FunctionContext)927{928PADAPTER adapter;929struct beamforming_info *info;930struct sounding_info *sounding;931struct beamformee_entry *bfee;932933934RTW_WARN("+%s\n", __FUNCTION__);935936adapter = (PADAPTER)FunctionContext;937info = GET_BEAMFORM_INFO(adapter);938sounding = &info->sounding_info;939940if (SOUNDING_STATE_SU_START == sounding->state) {941sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT;942RTW_ERR("%s: Set to SU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__);943/* SU BFee */944bfee = &info->bfee_entry[sounding->su_bfee_curidx];945bfee->bSoundingTimeout = _TRUE;946RTW_WARN("%s: The BFee entry[%d] is Sounding Timeout!\n", __FUNCTION__, sounding->su_bfee_curidx);947} else if (SOUNDING_STATE_MU_START == sounding->state) {948sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT;949RTW_ERR("%s: Set to MU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__);950} else {951RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state);952return;953}954955rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1);956}957958static struct beamformer_entry *_bfer_get_free_entry(PADAPTER adapter)959{960u8 i = 0;961struct beamforming_info *info;962struct beamformer_entry *bfer;963964965info = GET_BEAMFORM_INFO(adapter);966967for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {968bfer = &info->bfer_entry[i];969if (bfer->used == _FALSE)970return bfer;971}972973return NULL;974}975976static struct beamformer_entry *_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra)977{978u8 i = 0;979struct beamforming_info *info;980struct beamformer_entry *bfer;981982983info = GET_BEAMFORM_INFO(adapter);984985for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {986bfer = &info->bfer_entry[i];987if (bfer->used == _FALSE)988continue;989if (_rtw_memcmp(ra, bfer->mac_addr, ETH_ALEN) == _TRUE)990return bfer;991}992993return NULL;994}995996static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter,997struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering)998{999struct mlme_priv *mlme;1000struct beamforming_info *info;1001struct beamformer_entry *bfer;1002u8 *bssid;1003u16 val16;1004u8 i;100510061007mlme = &adapter->mlmepriv;1008info = GET_BEAMFORM_INFO(adapter);10091010bfer = _bfer_get_entry_by_addr(adapter, sta->cmn.mac_addr);1011if (!bfer) {1012bfer = _bfer_get_free_entry(adapter);1013if (!bfer)1014return NULL;1015}10161017bfer->used = _TRUE;1018_get_txvector_parameter(adapter, sta, &bfer->g_id, &bfer->p_aid);1019_rtw_memcpy(bfer->mac_addr, sta->cmn.mac_addr, ETH_ALEN);1020bfer->cap = bf_cap;1021bfer->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;1022bfer->NumofSoundingDim = sounding_dim;10231024if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_MU)) {1025info->beamformer_mu_cnt += 1;1026bfer->aid = sta->cmn.aid;1027} else if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {1028info->beamformer_su_cnt += 1;10291030/* Record HW idx info */1031for (i = 0; i < MAX_NUM_BEAMFORMER_SU; i++) {1032if ((info->beamformer_su_reg_maping & BIT(i)) == 0) {1033info->beamformer_su_reg_maping |= BIT(i);1034bfer->su_reg_index = i;1035break;1036}1037}1038RTW_INFO("%s: Add BFer entry beamformer_su_reg_maping=%#x, su_reg_index=%d\n",1039__FUNCTION__, info->beamformer_su_reg_maping, bfer->su_reg_index);1040}10411042return bfer;1043}10441045static void _bfer_remove_entry(PADAPTER adapter, struct beamformer_entry *entry)1046{1047struct beamforming_info *info;104810491050info = GET_BEAMFORM_INFO(adapter);10511052entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT;10531054if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_MU)) {1055info->beamformer_mu_cnt -= 1;1056_rtw_memset(entry->gid_valid, 0, 8);1057_rtw_memset(entry->user_position, 0, 16);1058} else if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {1059info->beamformer_su_cnt -= 1;1060}10611062if (info->beamformer_mu_cnt == 0)1063info->beamforming_cap &= ~BEAMFORMEE_CAP_VHT_MU;1064if (info->beamformer_su_cnt == 0)1065info->beamforming_cap &= ~(BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT);1066}10671068static u8 _bfer_set_entry_gid(PADAPTER adapter, u8 *addr, u8 *gid, u8 *position)1069{1070struct beamformer_entry bfer;10711072memset(&bfer, 0, sizeof(bfer));1073memcpy(bfer.mac_addr, addr, ETH_ALEN);10741075/* Parsing Membership Status Array */1076memcpy(bfer.gid_valid, gid, 8);10771078/* Parsing User Position Array */1079memcpy(bfer.user_position, position, 16);10801081/* Config HW GID table */1082rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8 *) &bfer,1083sizeof(bfer), 1);10841085return _SUCCESS;1086}10871088static struct beamformee_entry *_bfee_get_free_entry(PADAPTER adapter)1089{1090u8 i = 0;1091struct beamforming_info *info;1092struct beamformee_entry *bfee;109310941095info = GET_BEAMFORM_INFO(adapter);10961097for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {1098bfee = &info->bfee_entry[i];1099if (bfee->used == _FALSE)1100return bfee;1101}11021103return NULL;1104}11051106static struct beamformee_entry *_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra)1107{1108u8 i = 0;1109struct beamforming_info *info;1110struct beamformee_entry *bfee;111111121113info = GET_BEAMFORM_INFO(adapter);11141115for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {1116bfee = &info->bfee_entry[i];1117if (bfee->used == _FALSE)1118continue;1119if (_rtw_memcmp(ra, bfee->mac_addr, ETH_ALEN) == _TRUE)1120return bfee;1121}11221123return NULL;1124}11251126static u8 _bfee_get_first_su_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore)1127{1128struct beamforming_info *info;1129struct beamformee_entry *bfee;1130u8 i;113111321133info = GET_BEAMFORM_INFO(adapter);11341135for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {1136bfee = &info->bfee_entry[i];1137if (ignore && (bfee == ignore))1138continue;1139if (bfee->used == _FALSE)1140continue;1141if ((!TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU))1142&& TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT))1143return i;1144}11451146return 0xFF;1147}11481149/*1150* Description:1151* Get the first entry index of MU Beamformee.1152*1153* Return Value:1154* Index of the first MU sta, or 0xFF for invalid index.1155*1156* 2015.05.25. Created by tynli.1157*1158*/1159static u8 _bfee_get_first_mu_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore)1160{1161struct beamforming_info *info;1162struct beamformee_entry *bfee;1163u8 i;116411651166info = GET_BEAMFORM_INFO(adapter);11671168for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {1169bfee = &info->bfee_entry[i];1170if (ignore && (bfee == ignore))1171continue;1172if (bfee->used == _FALSE)1173continue;1174if (TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU))1175return i;1176}11771178return 0xFF;1179}11801181static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter,1182struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering)1183{1184struct mlme_priv *mlme;1185struct beamforming_info *info;1186struct beamformee_entry *bfee;1187u8 *bssid;1188u16 val16;1189u8 i;119011911192mlme = &adapter->mlmepriv;1193info = GET_BEAMFORM_INFO(adapter);11941195bfee = _bfee_get_entry_by_addr(adapter, sta->cmn.mac_addr);1196if (!bfee) {1197bfee = _bfee_get_free_entry(adapter);1198if (!bfee)1199return NULL;1200}12011202bfee->used = _TRUE;1203bfee->aid = sta->cmn.aid;1204bfee->mac_id = sta->cmn.mac_id;1205bfee->sound_bw = sta->cmn.bw_mode;12061207_get_txvector_parameter(adapter, sta, &bfee->g_id, &bfee->p_aid);1208sta->cmn.bf_info.g_id = bfee->g_id;1209sta->cmn.bf_info.p_aid = bfee->p_aid;12101211_rtw_memcpy(bfee->mac_addr, sta->cmn.mac_addr, ETH_ALEN);1212bfee->txbf = _FALSE;1213bfee->sounding = _FALSE;1214bfee->sound_period = 40;1215_sounding_update_min_period(adapter, bfee->sound_period, _FALSE);1216bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, info->sounding_info.min_sounding_period);1217bfee->cap = bf_cap;1218bfee->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;12191220bfee->bCandidateSoundingPeer = _FALSE;1221bfee->bSoundingTimeout = _FALSE;1222bfee->bDeleteSounding = _FALSE;1223bfee->bApplySounding = _TRUE;12241225bfee->tx_timestamp = 0;1226bfee->tx_bytes = 0;12271228bfee->LogStatusFailCnt = 0;1229bfee->NumofSoundingDim = sounding_dim;1230bfee->comp_steering_num_of_bfer = comp_steering;1231bfee->bSuspendSUCap = _FALSE;12321233if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_MU)) {1234info->beamformee_mu_cnt += 1;1235info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, NULL);12361237if (_TRUE == info->bEnableSUTxBFWorkAround) {1238/* When the first MU BFee added, discard SU BFee bfee's capability */1239if ((info->beamformee_mu_cnt == 1) && (info->beamformee_su_cnt > 0)) {1240if (info->TargetSUBFee) {1241info->TargetSUBFee->bSuspendSUCap = _TRUE;1242info->TargetSUBFee->bDeleteSounding = _TRUE;1243} else {1244RTW_ERR("%s: UNEXPECTED!! info->TargetSUBFee is NULL!", __FUNCTION__);1245}1246info->TargetSUBFee = NULL;1247_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));1248rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0);1249}1250}12511252/* Record HW idx info */1253for (i = 0; i < MAX_NUM_BEAMFORMEE_MU; i++) {1254if ((info->beamformee_mu_reg_maping & BIT(i)) == 0) {1255info->beamformee_mu_reg_maping |= BIT(i);1256bfee->mu_reg_index = i;1257break;1258}1259}1260RTW_INFO("%s: Add BFee entry beamformee_mu_reg_maping=%#x, mu_reg_index=%d\n",1261__FUNCTION__, info->beamformee_mu_reg_maping, bfee->mu_reg_index);12621263} else if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {1264info->beamformee_su_cnt += 1;12651266if (_TRUE == info->bEnableSUTxBFWorkAround) {1267/* Record the first SU BFee index. We only allow the first SU BFee to be sound */1268if ((info->beamformee_su_cnt == 1) && (info->beamformee_mu_cnt == 0)) {1269info->TargetSUBFee = bfee;1270_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));1271bfee->bSuspendSUCap = _FALSE;1272} else {1273bfee->bSuspendSUCap = _TRUE;1274}1275}12761277/* Record HW idx info */1278for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) {1279if ((info->beamformee_su_reg_maping & BIT(i)) == 0) {1280info->beamformee_su_reg_maping |= BIT(i);1281bfee->su_reg_index = i;1282break;1283}1284}1285RTW_INFO("%s: Add BFee entry beamformee_su_reg_maping=%#x, su_reg_index=%d\n",1286__FUNCTION__, info->beamformee_su_reg_maping, bfee->su_reg_index);1287}12881289return bfee;1290}12911292static void _bfee_remove_entry(PADAPTER adapter, struct beamformee_entry *entry)1293{1294struct beamforming_info *info;1295u8 idx;129612971298info = GET_BEAMFORM_INFO(adapter);12991300entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT;13011302if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_MU)) {1303info->beamformee_mu_cnt -= 1;1304info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, entry);13051306if (_TRUE == info->bEnableSUTxBFWorkAround) {1307if ((info->beamformee_mu_cnt == 0) && (info->beamformee_su_cnt > 0)) {1308idx = _bfee_get_first_su_entry_idx(adapter, NULL);1309info->TargetSUBFee = &info->bfee_entry[idx];1310_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));1311info->TargetSUBFee->bSuspendSUCap = _FALSE;1312}1313}1314} else if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {1315info->beamformee_su_cnt -= 1;13161317/* When the target SU BFee leaves, disable workaround */1318if ((_TRUE == info->bEnableSUTxBFWorkAround)1319&& (entry == info->TargetSUBFee)) {1320entry->bSuspendSUCap = _TRUE;1321info->TargetSUBFee = NULL;1322_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));1323rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0);1324}1325}13261327if (info->beamformee_mu_cnt == 0)1328info->beamforming_cap &= ~BEAMFORMER_CAP_VHT_MU;1329if (info->beamformee_su_cnt == 0)1330info->beamforming_cap &= ~(BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT);13311332_sounding_update_min_period(adapter, 0, _TRUE);1333}13341335static enum beamforming_cap _bfee_get_entry_cap_by_macid(PADAPTER adapter, u8 macid)1336{1337struct beamforming_info *info;1338struct beamformee_entry *bfee;1339u8 i;134013411342info = GET_BEAMFORM_INFO(adapter);13431344for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {1345bfee = &info->bfee_entry[i];1346if (bfee->used == _FALSE)1347continue;1348if (bfee->mac_id == macid)1349return bfee->cap;1350}13511352return BEAMFORMING_CAP_NONE;1353}13541355static void _beamforming_enter(PADAPTER adapter, void *p)1356{1357struct mlme_priv *mlme;1358struct ht_priv *htpriv;1359#ifdef CONFIG_80211AC_VHT1360struct vht_priv *vhtpriv;1361#endif1362struct mlme_ext_priv *mlme_ext;1363struct sta_info *sta, *sta_copy;1364struct beamforming_info *info;1365struct beamformer_entry *bfer = NULL;1366struct beamformee_entry *bfee = NULL;1367u8 wireless_mode;1368u8 sta_bf_cap;1369u8 sounding_dim = 0; /* number of sounding dimensions */1370u8 comp_steering_num = 0; /* compressed steering number */137113721373mlme = &adapter->mlmepriv;1374htpriv = &mlme->htpriv;1375#ifdef CONFIG_80211AC_VHT1376vhtpriv = &mlme->vhtpriv;1377#endif1378mlme_ext = &adapter->mlmeextpriv;1379info = GET_BEAMFORM_INFO(adapter);13801381sta_copy = (struct sta_info *)p;1382sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->cmn.mac_addr);1383if (!sta) {1384RTW_ERR("%s: Cann't find STA info for " MAC_FMT "\n",1385__FUNCTION__, MAC_ARG(sta_copy->cmn.mac_addr));1386return;1387}1388if (sta != sta_copy) {1389RTW_WARN("%s: Origin sta(fake)=%p realsta=%p for " MAC_FMT "\n",1390__FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->cmn.mac_addr));1391}13921393/* The current setting does not support Beaforming */1394wireless_mode = sta->wireless_mode;1395if ((is_supported_ht(wireless_mode) == _FALSE)1396&& (is_supported_vht(wireless_mode) == _FALSE)) {1397RTW_WARN("%s: Not support HT or VHT mode\n", __FUNCTION__);1398return;1399}14001401if ((0 == htpriv->beamform_cap)1402#ifdef CONFIG_80211AC_VHT1403&& (0 == vhtpriv->beamform_cap)1404#endif1405) {1406RTW_INFO("The configuration disabled Beamforming! Skip...\n");1407return;1408}14091410_get_sta_beamform_cap(adapter, sta,1411&sta_bf_cap, &sounding_dim, &comp_steering_num);1412RTW_INFO("STA Beamforming Capability=0x%02X\n", sta_bf_cap);1413if (sta_bf_cap == BEAMFORMING_CAP_NONE)1414return;1415if ((sta_bf_cap & BEAMFORMEE_CAP_HT_EXPLICIT)1416|| (sta_bf_cap & BEAMFORMEE_CAP_VHT_SU)1417|| (sta_bf_cap & BEAMFORMEE_CAP_VHT_MU))1418sta_bf_cap |= BEAMFORMEE_CAP;1419if ((sta_bf_cap & BEAMFORMER_CAP_HT_EXPLICIT)1420|| (sta_bf_cap & BEAMFORMER_CAP_VHT_SU)1421|| (sta_bf_cap & BEAMFORMER_CAP_VHT_MU))1422sta_bf_cap |= BEAMFORMER_CAP;14231424if (sta_bf_cap & BEAMFORMER_CAP) {1425/* The other side is beamformer */1426bfer = _bfer_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num);1427if (!bfer)1428RTW_ERR("%s: Fail to allocate bfer entry!\n", __FUNCTION__);1429}1430if (sta_bf_cap & BEAMFORMEE_CAP) {1431/* The other side is beamformee */1432bfee = _bfee_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num);1433if (!bfee)1434RTW_ERR("%s: Fail to allocate bfee entry!\n", __FUNCTION__);1435}1436if (!bfer && !bfee)1437return;14381439rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8*)sta);14401441/* Perform sounding if there is BFee */1442if ((info->beamformee_su_cnt != 0)1443|| (info->beamformee_mu_cnt != 0)) {1444if (SOUNDING_STATE_NONE == info->sounding_info.state) {1445info->sounding_info.state = SOUNDING_STATE_INIT;1446/* Start sounding after 2 sec */1447_set_timer(&info->sounding_timer, 2000);1448}1449}1450}14511452static void _beamforming_reset(PADAPTER adapter)1453{1454RTW_ERR("%s: Not ready!!\n", __FUNCTION__);1455}14561457static void _beamforming_leave(PADAPTER adapter, u8 *ra)1458{1459struct beamforming_info *info;1460struct beamformer_entry *bfer = NULL;1461struct beamformee_entry *bfee = NULL;1462u8 bHwStateAddInit = _FALSE;146314641465RTW_INFO("+%s\n", __FUNCTION__);14661467info = GET_BEAMFORM_INFO(adapter);1468bfer = _bfer_get_entry_by_addr(adapter, ra);1469bfee = _bfee_get_entry_by_addr(adapter, ra);14701471if (!bfer && !bfee) {1472RTW_WARN("%s: " MAC_FMT " is neither beamforming ee or er!!\n",1473__FUNCTION__, MAC_ARG(ra));1474return;1475}14761477if (bfer)1478_bfer_remove_entry(adapter, bfer);14791480if (bfee)1481_bfee_remove_entry(adapter, bfee);14821483rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, ra);14841485/* Stop sounding if there is no any BFee */1486if ((info->beamformee_su_cnt == 0)1487&& (info->beamformee_mu_cnt == 0)) {1488_cancel_timer_ex(&info->sounding_timer);1489_sounding_init(&info->sounding_info);1490}14911492RTW_INFO("-%s\n", __FUNCTION__);1493}14941495static void _beamforming_sounding_down(PADAPTER adapter, u8 status)1496{1497struct beamforming_info *info;1498struct sounding_info *sounding;1499struct beamformee_entry *bfee;150015011502info = GET_BEAMFORM_INFO(adapter);1503sounding = &info->sounding_info;15041505RTW_INFO("+%s: sounding=%d, status=0x%02x\n", __FUNCTION__, sounding->state, status);15061507if (sounding->state == SOUNDING_STATE_MU_START) {1508RTW_INFO("%s: MU sounding done\n", __FUNCTION__);1509sounding->state = SOUNDING_STATE_MU_SOUNDDOWN;1510RTW_INFO("%s: Set to SOUNDING_STATE_MU_SOUNDDOWN\n", __FUNCTION__);1511info->SetHalSoundownOnDemandCnt++;1512rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);1513} else if (sounding->state == SOUNDING_STATE_SU_START) {1514RTW_INFO("%s: SU entry[%d] sounding down\n", __FUNCTION__, sounding->su_bfee_curidx);1515bfee = &info->bfee_entry[sounding->su_bfee_curidx];1516sounding->state = SOUNDING_STATE_SU_SOUNDDOWN;1517RTW_INFO("%s: Set to SOUNDING_STATE_SU_SOUNDDOWN\n", __FUNCTION__);15181519/*1520* <tynli_note>1521* bfee->bSoundingTimeout this flag still cannot avoid1522* old sound down event happens in the new sounding period.1523* 2015.12.101524*/1525if (_TRUE == bfee->bSoundingTimeout) {1526RTW_WARN("%s: The entry[%d] is bSoundingTimeout!\n", __FUNCTION__, sounding->su_bfee_curidx);1527bfee->bSoundingTimeout = _FALSE;1528return;1529}15301531if (_TRUE == status) {1532/* success */1533bfee->LogStatusFailCnt = 0;1534info->SetHalSoundownOnDemandCnt++;1535rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);1536} else if (_TRUE == bfee->bDeleteSounding) {1537RTW_WARN("%s: Delete entry[%d] sounding info!\n", __FUNCTION__, sounding->su_bfee_curidx);1538rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);1539bfee->bDeleteSounding = _FALSE;1540} else {1541bfee->LogStatusFailCnt++;1542RTW_WARN("%s: LogStatusFailCnt=%d\n", __FUNCTION__, bfee->LogStatusFailCnt);1543if (bfee->LogStatusFailCnt > 30) {1544RTW_ERR("%s: LogStatusFailCnt > 30, Stop SOUNDING!!\n", __FUNCTION__);1545rtw_bf_cmd(adapter, BEAMFORMING_CTRL_LEAVE, bfee->mac_addr, ETH_ALEN, 1);1546}1547}1548} else {1549RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state);1550return;1551}15521553rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 0);1554}15551556static void _c2h_snd_txbf(PADAPTER adapter, u8 *buf, u8 buf_len)1557{1558struct beamforming_info *info;1559u8 res;15601561info = GET_BEAMFORM_INFO(adapter);15621563_cancel_timer_ex(&info->sounding_timeout_timer);15641565res = C2H_SND_TXBF_GET_SND_RESULT(buf) ? _TRUE : _FALSE;1566RTW_INFO("+%s: %s\n", __FUNCTION__, res==_TRUE?"Success":"Fail!");15671568rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1);1569}15701571/*1572* Description:1573* This function is for phydm only1574*/1575enum beamforming_cap rtw_bf_bfee_get_entry_cap_by_macid(void *mlme, u8 macid)1576{1577PADAPTER adapter;1578enum beamforming_cap cap = BEAMFORMING_CAP_NONE;157915801581adapter = mlme_to_adapter((struct mlme_priv *)mlme);1582cap = _bfee_get_entry_cap_by_macid(adapter, macid);15831584return cap;1585}15861587struct beamformer_entry *rtw_bf_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra)1588{1589return _bfer_get_entry_by_addr(adapter, ra);1590}15911592struct beamformee_entry *rtw_bf_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra)1593{1594return _bfee_get_entry_by_addr(adapter, ra);1595}15961597void rtw_bf_get_ndpa_packet(PADAPTER adapter, union recv_frame *precv_frame)1598{1599RTW_DBG("+%s\n", __FUNCTION__);1600}16011602u32 rtw_bf_get_report_packet(PADAPTER adapter, union recv_frame *precv_frame)1603{1604u32 ret = _SUCCESS;1605struct beamforming_info *info;1606struct beamformee_entry *bfee = NULL;1607u8 *pframe;1608u32 frame_len;1609u8 *ta;1610u8 *frame_body;1611u8 category, action;1612u8 *pMIMOCtrlField, *pCSIMatrix;1613u8 Nc = 0, Nr = 0, CH_W = 0, Ng = 0, CodeBook = 0;1614u16 CSIMatrixLen = 0;161516161617RTW_INFO("+%s\n", __FUNCTION__);16181619info = GET_BEAMFORM_INFO(adapter);1620pframe = precv_frame->u.hdr.rx_data;1621frame_len = precv_frame->u.hdr.len;16221623/* Memory comparison to see if CSI report is the same with previous one */1624ta = get_addr2_ptr(pframe);1625bfee = _bfee_get_entry_by_addr(adapter, ta);1626if (!bfee)1627return _FAIL;16281629frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);1630category = frame_body[0];1631action = frame_body[1];16321633if ((category == RTW_WLAN_CATEGORY_VHT)1634&& (action == RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING)) {1635pMIMOCtrlField = pframe + 26;1636Nc = (*pMIMOCtrlField) & 0x7;1637Nr = ((*pMIMOCtrlField) & 0x38) >> 3;1638CH_W = (((*pMIMOCtrlField) & 0xC0) >> 6);1639Ng = (*(pMIMOCtrlField+1)) & 0x3;1640CodeBook = ((*(pMIMOCtrlField+1)) & 0x4) >> 2;1641/*1642* 24+(1+1+3)+21643* ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)1644*/1645pCSIMatrix = pMIMOCtrlField + 3 + Nc;1646CSIMatrixLen = frame_len - 26 - 3 - Nc;1647info->TargetCSIInfo.bVHT = _TRUE;1648} else if ((category == RTW_WLAN_CATEGORY_HT)1649&& (action == RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING)) {1650pMIMOCtrlField = pframe + 26;1651Nc = (*pMIMOCtrlField) & 0x3;1652Nr = ((*pMIMOCtrlField) & 0xC) >> 2;1653CH_W = ((*pMIMOCtrlField) & 0x10) >> 4;1654Ng = ((*pMIMOCtrlField) & 0x60) >> 5;1655CodeBook = ((*(pMIMOCtrlField+1)) & 0x6) >> 1;1656/*1657* 24+(1+1+6)+21658* ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)1659*/1660pCSIMatrix = pMIMOCtrlField + 6 + Nr;1661CSIMatrixLen = frame_len - 26 - 6 - Nr;1662info->TargetCSIInfo.bVHT = _FALSE;1663}16641665/* Update current CSI report info */1666if ((_TRUE == info->bEnableSUTxBFWorkAround)1667&& (info->TargetSUBFee == bfee)) {1668if ((info->TargetCSIInfo.Nc != Nc) || (info->TargetCSIInfo.Nr != Nr) ||1669(info->TargetCSIInfo.ChnlWidth != CH_W) || (info->TargetCSIInfo.Ng != Ng) ||1670(info->TargetCSIInfo.CodeBook != CodeBook)) {1671info->TargetCSIInfo.Nc = Nc;1672info->TargetCSIInfo.Nr = Nr;1673info->TargetCSIInfo.ChnlWidth = CH_W;1674info->TargetCSIInfo.Ng = Ng;1675info->TargetCSIInfo.CodeBook = CodeBook;16761677rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 1);1678}1679}16801681RTW_INFO("%s: pkt type=%d-%d, Nc=%d, Nr=%d, CH_W=%d, Ng=%d, CodeBook=%d\n",1682__FUNCTION__, category, action, Nc, Nr, CH_W, Ng, CodeBook);16831684return ret;1685}16861687u8 rtw_bf_send_vht_gid_mgnt_packet(PADAPTER adapter, u8 *ra, u8 *gid, u8 *position)1688{1689/* General */1690struct xmit_priv *xmitpriv;1691struct mlme_priv *mlmepriv;1692struct xmit_frame *pmgntframe;1693/* MISC */1694struct pkt_attrib *attrib;1695struct rtw_ieee80211_hdr *wlanhdr;1696u8 *pframe, *ptr;169716981699xmitpriv = &adapter->xmitpriv;1700mlmepriv = &adapter->mlmepriv;17011702pmgntframe = alloc_mgtxmitframe(xmitpriv);1703if (!pmgntframe)1704return _FALSE;17051706/* update attribute */1707attrib = &pmgntframe->attrib;1708update_mgntframe_attrib(adapter, attrib);1709attrib->rate = MGN_6M;1710attrib->bwmode = CHANNEL_WIDTH_20;1711attrib->subtype = WIFI_ACTION;17121713_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);17141715pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET;1716wlanhdr = (struct rtw_ieee80211_hdr *)pframe;17171718wlanhdr->frame_ctl = 0;1719set_frame_sub_type(pframe, attrib->subtype);1720set_duration(pframe, 0);1721SetFragNum(pframe, 0);1722SetSeqNum(pframe, 0);17231724_rtw_memcpy(wlanhdr->addr1, ra, ETH_ALEN);1725_rtw_memcpy(wlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);1726_rtw_memcpy(wlanhdr->addr3, get_bssid(mlmepriv), ETH_ALEN);17271728pframe[24] = RTW_WLAN_CATEGORY_VHT;1729pframe[25] = RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT;1730/* Set Membership Status Array */1731ptr = pframe + 26;1732_rtw_memcpy(ptr, gid, 8);1733/* Set User Position Array */1734ptr = pframe + 34;1735_rtw_memcpy(ptr, position, 16);17361737attrib->pktlen = 54;1738attrib->last_txcmdsz = attrib->pktlen;17391740dump_mgntframe(adapter, pmgntframe);17411742return _TRUE;1743}17441745/*1746* Description:1747* On VHT GID management frame by an MU beamformee.1748*/1749void rtw_bf_get_vht_gid_mgnt_packet(PADAPTER adapter, union recv_frame *precv_frame)1750{1751u8 *pframe;1752u8 *ta, *gid, *position;175317541755RTW_DBG("+%s\n", __FUNCTION__);17561757pframe = precv_frame->u.hdr.rx_data;17581759/* Get address by Addr2 */1760ta = get_addr2_ptr(pframe);1761/* Remove signaling TA */1762ta[0] &= 0xFE;17631764/* Membership Status Array */1765gid = pframe + 26;1766/* User Position Array */1767position= pframe + 34;17681769_bfer_set_entry_gid(adapter, ta, gid, position);1770}17711772void rtw_bf_init(PADAPTER adapter)1773{1774struct beamforming_info *info;177517761777info = GET_BEAMFORM_INFO(adapter);1778info->beamforming_cap = BEAMFORMING_CAP_NONE;1779info->beamforming_state = BEAMFORMING_STATE_IDLE;1780/*1781info->bfee_entry[MAX_BEAMFORMEE_ENTRY_NUM];1782info->bfer_entry[MAX_BEAMFORMER_ENTRY_NUM];1783*/1784info->sounding_sequence = 0;1785info->beamformee_su_cnt = 0;1786info->beamformer_su_cnt = 0;1787info->beamformee_su_reg_maping = 0;1788info->beamformer_su_reg_maping = 0;1789info->beamformee_mu_cnt = 0;1790info->beamformer_mu_cnt = 0;1791info->beamformee_mu_reg_maping = 0;1792info->first_mu_bfee_index = 0xFF;1793info->mu_bfer_curidx = 0xFF;1794info->cur_csi_rpt_rate = HALMAC_OFDM24;17951796_sounding_init(&info->sounding_info);1797rtw_init_timer(&info->sounding_timer, adapter, _sounding_timer_handler, adapter);1798rtw_init_timer(&info->sounding_timeout_timer, adapter, _sounding_timeout_timer_handler, adapter);17991800info->SetHalBFEnterOnDemandCnt = 0;1801info->SetHalBFLeaveOnDemandCnt = 0;1802info->SetHalSoundownOnDemandCnt = 0;18031804info->bEnableSUTxBFWorkAround = _TRUE;1805info->TargetSUBFee = NULL;18061807info->sounding_running = 0;1808}18091810void rtw_bf_cmd_hdl(PADAPTER adapter, u8 type, u8 *pbuf)1811{1812switch (type) {1813case BEAMFORMING_CTRL_ENTER:1814_beamforming_enter(adapter, pbuf);1815break;18161817case BEAMFORMING_CTRL_LEAVE:1818if (pbuf == NULL)1819_beamforming_reset(adapter);1820else1821_beamforming_leave(adapter, pbuf);1822break;18231824case BEAMFORMING_CTRL_START_PERIOD:1825_sounding_handler(adapter);1826break;18271828case BEAMFORMING_CTRL_END_PERIOD:1829_beamforming_sounding_down(adapter, *pbuf);1830break;18311832case BEAMFORMING_CTRL_SET_GID_TABLE:1833rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, pbuf);1834break;18351836case BEAMFORMING_CTRL_SET_CSI_REPORT:1837rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_CSI_REPORT, pbuf);1838break;18391840default:1841break;1842}1843}18441845u8 rtw_bf_cmd(PADAPTER adapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)1846{1847struct cmd_obj *ph2c;1848struct drvextra_cmd_parm *pdrvextra_cmd_parm;1849struct cmd_priv *pcmdpriv = &adapter->cmdpriv;1850u8 *wk_buf;1851u8 res = _SUCCESS;185218531854if (!enqueue) {1855rtw_bf_cmd_hdl(adapter, type, pbuf);1856goto exit;1857}18581859ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));1860if (ph2c == NULL) {1861res = _FAIL;1862goto exit;1863}18641865pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));1866if (pdrvextra_cmd_parm == NULL) {1867rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));1868res = _FAIL;1869goto exit;1870}18711872if (pbuf != NULL) {1873wk_buf = rtw_zmalloc(size);1874if (wk_buf == NULL) {1875rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));1876rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));1877res = _FAIL;1878goto exit;1879}18801881_rtw_memcpy(wk_buf, pbuf, size);1882} else {1883wk_buf = NULL;1884size = 0;1885}18861887pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;1888pdrvextra_cmd_parm->type = type;1889pdrvextra_cmd_parm->size = size;1890pdrvextra_cmd_parm->pbuf = wk_buf;18911892init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));18931894res = rtw_enqueue_cmd(pcmdpriv, ph2c);18951896exit:1897return res;1898}18991900void rtw_bf_update_attrib(PADAPTER adapter, struct pkt_attrib *attrib, struct sta_info *sta)1901{1902if (sta) {1903attrib->txbf_g_id = sta->cmn.bf_info.g_id;1904attrib->txbf_p_aid = sta->cmn.bf_info.p_aid;1905}1906}19071908void rtw_bf_c2h_handler(PADAPTER adapter, u8 id, u8 *buf, u8 buf_len)1909{1910switch (id) {1911case CMD_ID_C2H_SND_TXBF:1912_c2h_snd_txbf(adapter, buf, buf_len);1913break;1914}1915}19161917#define toMbps(bytes, secs) (rtw_division64(bytes >> 17, secs))1918void rtw_bf_update_traffic(PADAPTER adapter)1919{1920struct beamforming_info *info;1921struct sounding_info *sounding;1922struct beamformee_entry *bfee;1923struct sta_info *sta;1924u8 bfee_cnt, sounding_idx, i;1925u16 tp[MAX_BEAMFORMEE_ENTRY_NUM] = {0};1926u8 tx_rate[MAX_BEAMFORMEE_ENTRY_NUM] = {0};1927u64 tx_bytes, last_bytes;1928u32 time;1929systime last_timestamp;1930u8 set_timer = _FALSE;193119321933info = GET_BEAMFORM_INFO(adapter);1934sounding = &info->sounding_info;19351936/* Check any bfee exist? */1937bfee_cnt = info->beamformee_su_cnt + info->beamformee_mu_cnt;1938if (bfee_cnt == 0)1939return;19401941for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {1942bfee = &info->bfee_entry[i];1943if (_FALSE == bfee->used)1944continue;19451946sta = rtw_get_stainfo(&adapter->stapriv, bfee->mac_addr);1947if (!sta) {1948RTW_ERR("%s: Cann't find sta_info for " MAC_FMT "!\n", __FUNCTION__, MAC_ARG(bfee->mac_addr));1949continue;1950}19511952last_timestamp = bfee->tx_timestamp;1953last_bytes = bfee->tx_bytes;1954bfee->tx_timestamp = rtw_get_current_time();1955bfee->tx_bytes = sta->sta_stats.tx_bytes;1956if (last_timestamp) {1957if (bfee->tx_bytes >= last_bytes)1958tx_bytes = bfee->tx_bytes - last_bytes;1959else1960tx_bytes = bfee->tx_bytes + (~last_bytes);1961time = rtw_get_time_interval_ms(last_timestamp, bfee->tx_timestamp);1962time = (time > 1000) ? time/1000 : 1;1963tp[i] = toMbps(tx_bytes, time);1964tx_rate[i] = rtw_get_current_tx_rate(adapter, sta);1965RTW_INFO("%s: BFee idx(%d), MadId(%d), TxTP=%lld bytes (%d Mbps), txrate=%d\n",1966__FUNCTION__, i, bfee->mac_id, tx_bytes, tp[i], tx_rate[i]);1967}1968}19691970sounding_idx = phydm_get_beamforming_sounding_info(GET_PDM_ODM(adapter), tp, MAX_BEAMFORMEE_ENTRY_NUM, tx_rate);19711972for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {1973bfee = &info->bfee_entry[i];1974if (_FALSE == bfee->used) {1975if (sounding_idx & BIT(i))1976RTW_WARN("%s: bfee(%d) not in used but need sounding?!\n", __FUNCTION__, i);1977continue;1978}19791980if (sounding_idx & BIT(i)) {1981if (_FALSE == bfee->bApplySounding) {1982bfee->bApplySounding = _TRUE;1983bfee->SoundCnt = 0;1984set_timer = _TRUE;1985}1986} else {1987if (_TRUE == bfee->bApplySounding) {1988bfee->bApplySounding = _FALSE;1989bfee->bDeleteSounding = _TRUE;1990bfee->SoundCnt = 0;1991set_timer = _TRUE;1992}1993}1994}19951996if (_TRUE == set_timer) {1997if (SOUNDING_STATE_NONE == info->sounding_info.state) {1998info->sounding_info.state = SOUNDING_STATE_INIT;1999_set_timer(&info->sounding_timer, 0);2000}2001}2002}20032004#else /* !RTW_BEAMFORMING_VERSION_2 */20052006/*PHYDM_BF - (BEAMFORMING_SUPPORT == 1)*/2007u32 rtw_beamforming_get_report_frame(PADAPTER Adapter, union recv_frame *precv_frame)2008{2009u32 ret = _SUCCESS;20102011PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);2012struct dm_struct *pDM_Odm = &(pHalData->odmpriv);20132014ret = beamforming_get_report_frame(pDM_Odm, precv_frame);2015return ret;2016}20172018void rtw_beamforming_get_ndpa_frame(PADAPTER Adapter, union recv_frame *precv_frame)2019{2020PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);2021struct dm_struct *pDM_Odm = &(pHalData->odmpriv);20222023beamforming_get_ndpa_frame(pDM_Odm, precv_frame);2024}20252026void beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf)2027{2028PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);2029struct dm_struct *pDM_Odm = &(pHalData->odmpriv);20302031/*(BEAMFORMING_SUPPORT == 1)- for PHYDM beamfoming*/2032switch (type) {2033case BEAMFORMING_CTRL_ENTER: {2034struct sta_info *psta = (void *)pbuf;2035u16 staIdx = psta->cmn.mac_id;20362037beamforming_enter(pDM_Odm, staIdx, adapter_mac_addr(psta->padapter));2038break;2039}2040case BEAMFORMING_CTRL_LEAVE:2041beamforming_leave(pDM_Odm, pbuf);2042break;2043default:2044break;20452046}2047}20482049u8 beamforming_wk_cmd(_adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)2050{2051struct cmd_obj *ph2c;2052struct drvextra_cmd_parm *pdrvextra_cmd_parm;2053struct cmd_priv *pcmdpriv = &padapter->cmdpriv;2054struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;2055struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);2056u8 res = _SUCCESS;20572058/*20170214 ad_hoc mode and mp_mode not support BF*/2059if ((padapter->registrypriv.mp_mode == 1)2060|| (pmlmeinfo->state == WIFI_FW_ADHOC_STATE))2061return res;20622063if (enqueue) {2064u8 *wk_buf;20652066ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));2067if (ph2c == NULL) {2068res = _FAIL;2069goto exit;2070}20712072pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));2073if (pdrvextra_cmd_parm == NULL) {2074rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));2075res = _FAIL;2076goto exit;2077}20782079if (pbuf != NULL) {2080wk_buf = rtw_zmalloc(size);2081if (wk_buf == NULL) {2082rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));2083rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));2084res = _FAIL;2085goto exit;2086}20872088_rtw_memcpy(wk_buf, pbuf, size);2089} else {2090wk_buf = NULL;2091size = 0;2092}20932094pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;2095pdrvextra_cmd_parm->type = type;2096pdrvextra_cmd_parm->size = size;2097pdrvextra_cmd_parm->pbuf = wk_buf;20982099init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));21002101res = rtw_enqueue_cmd(pcmdpriv, ph2c);2102} else2103beamforming_wk_hdl(padapter, type, pbuf);21042105exit:210621072108return res;2109}21102111void update_attrib_txbf_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta)2112{2113if (psta) {2114pattrib->txbf_g_id = psta->cmn.bf_info.g_id;2115pattrib->txbf_p_aid = psta->cmn.bf_info.p_aid;2116}2117}2118#endif /* !RTW_BEAMFORMING_VERSION_2 */21192120#endif /* CONFIG_BEAMFORMING */212121222123