Path: blob/master/ALFA-W1F1/RTL8814AU/hal/phydm/phydm_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* The full GNU General Public License is included in this distribution in the14* file called LICENSE.15*16* Contact Information:17* wlanfae <[email protected]>18* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,19* Hsinchu 300, Taiwan.20*21* Larry Finger <[email protected]>22*23*****************************************************************************/2425#include "mp_precomp.h"26#include "phydm_precomp.h"2728#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)29#if WPP_SOFTWARE_TRACE30#include "phydm_beamforming.tmh"31#endif32#endif3334#ifdef PHYDM_BEAMFORMING_SUPPORT3536void phydm_get_txbf_device_num(37void *dm_void,38u8 macid)39{40#if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) /*@For BDC*/41#if (DM_ODM_SUPPORT_TYPE == ODM_AP)4243struct dm_struct *dm = (struct dm_struct *)dm_void;44struct cmn_sta_info *sta = dm->phydm_sta_info[macid];45struct bf_cmn_info *bf = NULL;46struct _BF_DIV_COEX_ *dm_bdc_table = &dm->dm_bdc_table;47u8 act_as_bfer = 0;48u8 act_as_bfee = 0;4950if (is_sta_active(sta)) {51bf = &(sta->bf_info);52} else {53PHYDM_DBG(dm, DBG_TXBF, "[Warning] %s invalid sta_info\n",54__func__);55return;56}5758if (sta->support_wireless_set & WIRELESS_VHT) {59if (bf->vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMEE_ENABLE)60act_as_bfer = 1;6162if (bf->vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMER_ENABLE)63act_as_bfee = 1;6465} else if (sta->support_wireless_set & WIRELESS_HT) {66if (bf->ht_beamform_cap & BEAMFORMING_HT_BEAMFORMEE_ENABLE)67act_as_bfer = 1;6869if (bf->ht_beamform_cap & BEAMFORMING_HT_BEAMFORMER_ENABLE)70act_as_bfee = 1;71}7273if (act_as_bfer))74{ /* Our Device act as BFer */75dm_bdc_table->w_bfee_client[macid] = true;76dm_bdc_table->num_txbfee_client++;77}78else79dm_bdc_table->w_bfee_client[macid] = false;8081if (act_as_bfee))82{ /* Our Device act as BFee */83dm_bdc_table->w_bfer_client[macid] = true;84dm_bdc_table->num_txbfer_client++;85}86else87dm_bdc_table->w_bfer_client[macid] = false;8889#endif90#endif91}9293struct _RT_BEAMFORM_STAINFO *94phydm_sta_info_init(struct dm_struct *dm, u16 sta_idx, u8 *my_mac_addr)95{96struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;97struct _RT_BEAMFORM_STAINFO *entry = &beam_info->beamform_sta_info;98struct cmn_sta_info *cmn_sta = dm->phydm_sta_info[sta_idx];99//void *adapter = dm->adapter;100ADAPTER * adapter = dm->adapter;101#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)102PMGNT_INFO p_MgntInfo = &((adapter)->MgntInfo);103PRT_HIGH_THROUGHPUT p_ht_info = GET_HT_INFO(p_MgntInfo);104PRT_VERY_HIGH_THROUGHPUT p_vht_info = GET_VHT_INFO(p_MgntInfo);105#endif106107if (!is_sta_active(cmn_sta)) {108PHYDM_DBG(dm, DBG_TXBF, "%s => sta_info(mac_id:%d) failed\n",109__func__, sta_idx);110#if (DM_ODM_SUPPORT_TYPE == ODM_CE)111rtw_warn_on(1);112#endif113114return entry;115}116117#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)118/*odm_move_memory(dm, (PVOID)(entry->my_mac_addr),*/119/*(PVOID)(adapter->CurrentAddress), 6);*/120odm_move_memory(dm, entry->my_mac_addr, my_mac_addr, 6);121#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)122/*odm_move_memory(dm, entry->my_mac_addr,*/123/*adapter_mac_addr(sta->padapter), 6);*/124odm_move_memory(dm, entry->my_mac_addr, my_mac_addr, 6);125#endif126127entry->aid = cmn_sta->aid;128entry->ra = cmn_sta->mac_addr;129entry->mac_id = cmn_sta->mac_id;130entry->bw = cmn_sta->bw_mode;131entry->cur_beamform = cmn_sta->bf_info.ht_beamform_cap;132entry->ht_beamform_cap = cmn_sta->bf_info.ht_beamform_cap;133134#if ODM_IC_11AC_SERIES_SUPPORT135if (cmn_sta->support_wireless_set & WIRELESS_VHT) {136entry->cur_beamform_vht = cmn_sta->bf_info.vht_beamform_cap;137entry->vht_beamform_cap = cmn_sta->bf_info.vht_beamform_cap;138}139#endif140141#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) /*To Be Removed */142entry->ht_beamform_cap = p_ht_info->HtBeamformCap; /*To Be Removed*/143entry->vht_beamform_cap = p_vht_info->VhtBeamformCap; /*To Be Removed*/144145if (sta_idx == 0) { /*@client mode*/146#if ODM_IC_11AC_SERIES_SUPPORT147if (cmn_sta->support_wireless_set & WIRELESS_VHT)148entry->cur_beamform_vht = p_vht_info->VhtCurBeamform;149#endif150}151#endif152153PHYDM_DBG(dm, DBG_TXBF, "wireless_set = 0x%x, staidx = %d\n",154cmn_sta->support_wireless_set, sta_idx);155PHYDM_DBG(dm, DBG_TXBF,156"entry->cur_beamform = 0x%x, entry->cur_beamform_vht = 0x%x\n",157entry->cur_beamform, entry->cur_beamform_vht);158return entry;159}160void phydm_sta_info_update(161struct dm_struct *dm,162u16 sta_idx,163struct _RT_BEAMFORMEE_ENTRY *beamform_entry)164{165struct cmn_sta_info *sta = dm->phydm_sta_info[sta_idx];166167if (!is_sta_active(sta))168return;169170sta->bf_info.p_aid = beamform_entry->p_aid;171sta->bf_info.g_id = beamform_entry->g_id;172}173174struct _RT_BEAMFORMEE_ENTRY *175phydm_beamforming_get_bfee_entry_by_addr(176void *dm_void,177u8 *RA,178u8 *idx)179{180struct dm_struct *dm = (struct dm_struct *)dm_void;181u8 i = 0;182struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;183184for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {185if (beam_info->beamformee_entry[i].is_used && (eq_mac_addr(RA, beam_info->beamformee_entry[i].mac_addr))) {186*idx = i;187return &beam_info->beamformee_entry[i];188}189}190191return NULL;192}193194struct _RT_BEAMFORMER_ENTRY *195phydm_beamforming_get_bfer_entry_by_addr(196void *dm_void,197u8 *TA,198u8 *idx)199{200struct dm_struct *dm = (struct dm_struct *)dm_void;201u8 i = 0;202struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;203204for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {205if (beam_info->beamformer_entry[i].is_used && (eq_mac_addr(TA, beam_info->beamformer_entry[i].mac_addr))) {206*idx = i;207return &beam_info->beamformer_entry[i];208}209}210211return NULL;212}213214struct _RT_BEAMFORMEE_ENTRY *215phydm_beamforming_get_entry_by_mac_id(216void *dm_void,217u8 mac_id,218u8 *idx)219{220struct dm_struct *dm = (struct dm_struct *)dm_void;221u8 i = 0;222struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;223224for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {225if (beam_info->beamformee_entry[i].is_used && mac_id == beam_info->beamformee_entry[i].mac_id) {226*idx = i;227return &beam_info->beamformee_entry[i];228}229}230231return NULL;232}233234enum beamforming_cap235phydm_beamforming_get_entry_beam_cap_by_mac_id(236void *dm_void,237u8 mac_id)238{239struct dm_struct *dm = (struct dm_struct *)dm_void;240u8 i = 0;241struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;242enum beamforming_cap beamform_entry_cap = BEAMFORMING_CAP_NONE;243244for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {245if (beam_info->beamformee_entry[i].is_used && mac_id == beam_info->beamformee_entry[i].mac_id) {246beamform_entry_cap = beam_info->beamformee_entry[i].beamform_entry_cap;247i = BEAMFORMEE_ENTRY_NUM;248}249}250251return beamform_entry_cap;252}253254struct _RT_BEAMFORMEE_ENTRY *255phydm_beamforming_get_free_bfee_entry(256void *dm_void,257u8 *idx)258{259struct dm_struct *dm = (struct dm_struct *)dm_void;260u8 i = 0;261struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;262263for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {264if (beam_info->beamformee_entry[i].is_used == false) {265*idx = i;266return &beam_info->beamformee_entry[i];267}268}269return NULL;270}271272struct _RT_BEAMFORMER_ENTRY *273phydm_beamforming_get_free_bfer_entry(274void *dm_void,275u8 *idx)276{277struct dm_struct *dm = (struct dm_struct *)dm_void;278u8 i = 0;279struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;280281PHYDM_DBG(dm, DBG_TXBF, "%s ===>\n", __func__);282283for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {284if (beam_info->beamformer_entry[i].is_used == false) {285*idx = i;286return &beam_info->beamformer_entry[i];287}288}289return NULL;290}291292/*@293* Description: Get the first entry index of MU Beamformee.294*295* Return value: index of the first MU sta.296*297* 2015.05.25. Created by tynli.298*299*/300u8 phydm_beamforming_get_first_mu_bfee_entry_idx(301void *dm_void)302{303struct dm_struct *dm = (struct dm_struct *)dm_void;304u8 idx = 0xFF;305struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;306boolean is_found = false;307308for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {309if (beam_info->beamformee_entry[idx].is_used && beam_info->beamformee_entry[idx].is_mu_sta) {310PHYDM_DBG(dm, DBG_TXBF, "[%s] idx=%d!\n", __func__,311idx);312is_found = true;313break;314}315}316317if (!is_found)318idx = 0xFF;319320return idx;321}322323/*@Add SU BFee and MU BFee*/324struct _RT_BEAMFORMEE_ENTRY *325beamforming_add_bfee_entry(326void *dm_void,327struct _RT_BEAMFORM_STAINFO *sta,328enum beamforming_cap beamform_cap,329u8 num_of_sounding_dim,330u8 comp_steering_num_of_bfer,331u8 *idx)332{333struct dm_struct *dm = (struct dm_struct *)dm_void;334struct _RT_BEAMFORMEE_ENTRY *entry = phydm_beamforming_get_free_bfee_entry(dm, idx);335336PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);337338if (entry != NULL) {339entry->is_used = true;340entry->aid = sta->aid;341entry->mac_id = sta->mac_id;342entry->sound_bw = sta->bw;343odm_move_memory(dm, entry->my_mac_addr, sta->my_mac_addr, 6);344345if (phydm_acting_determine(dm, phydm_acting_as_ap)) {346/*@BSSID[44:47] xor BSSID[40:43]*/347u16 bssid = ((sta->my_mac_addr[5] & 0xf0) >> 4) ^ (sta->my_mac_addr[5] & 0xf);348/*@(dec(A) + dec(B)*32) mod 512*/349entry->p_aid = (sta->aid + bssid * 32) & 0x1ff;350entry->g_id = 63;351PHYDM_DBG(dm, DBG_TXBF,352"%s: BFee P_AID addressed to STA=%d\n",353__func__, entry->p_aid);354} else if (phydm_acting_determine(dm, phydm_acting_as_ibss)) {355/*@ad hoc mode*/356entry->p_aid = 0;357entry->g_id = 63;358PHYDM_DBG(dm, DBG_TXBF, "%s: BFee P_AID as IBSS=%d\n",359__func__, entry->p_aid);360} else {361/*@client mode*/362entry->p_aid = sta->ra[5];363/*@BSSID[39:47]*/364entry->p_aid = (entry->p_aid << 1) | (sta->ra[4] >> 7);365entry->g_id = 0;366PHYDM_DBG(dm, DBG_TXBF,367"%s: BFee P_AID addressed to AP=0x%X\n",368__func__, entry->p_aid);369}370cp_mac_addr(entry->mac_addr, sta->ra);371entry->is_txbf = false;372entry->is_sound = false;373entry->sound_period = 400;374entry->beamform_entry_cap = beamform_cap;375entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;376377/* @entry->log_seq = 0xff; Move to beamforming_add_bfer_entry*/378/* @entry->log_retry_cnt = 0; Move to beamforming_add_bfer_entry*/379/* @entry->LogSuccessCnt = 0; Move to beamforming_add_bfer_entry*/380381entry->log_status_fail_cnt = 0;382383entry->num_of_sounding_dim = num_of_sounding_dim;384entry->comp_steering_num_of_bfer = comp_steering_num_of_bfer;385386if (beamform_cap & BEAMFORMER_CAP_VHT_MU) {387dm->beamforming_info.beamformee_mu_cnt += 1;388entry->is_mu_sta = true;389dm->beamforming_info.first_mu_bfee_index = phydm_beamforming_get_first_mu_bfee_entry_idx(dm);390} else if (beamform_cap & (BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP_HT_EXPLICIT)) {391dm->beamforming_info.beamformee_su_cnt += 1;392entry->is_mu_sta = false;393}394395return entry;396} else397return NULL;398}399400/*@Add SU BFee and MU BFer*/401struct _RT_BEAMFORMER_ENTRY *402beamforming_add_bfer_entry(403void *dm_void,404struct _RT_BEAMFORM_STAINFO *sta,405enum beamforming_cap beamform_cap,406u8 num_of_sounding_dim,407u8 *idx)408{409struct dm_struct *dm = (struct dm_struct *)dm_void;410struct _RT_BEAMFORMER_ENTRY *entry = phydm_beamforming_get_free_bfer_entry(dm, idx);411412PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);413414if (entry != NULL) {415entry->is_used = true;416odm_move_memory(dm, entry->my_mac_addr, sta->my_mac_addr, 6);417if (phydm_acting_determine(dm, phydm_acting_as_ap)) {418/*@BSSID[44:47] xor BSSID[40:43]*/419u16 bssid = ((sta->my_mac_addr[5] & 0xf0) >> 4) ^ (sta->my_mac_addr[5] & 0xf);420421entry->p_aid = (sta->aid + bssid * 32) & 0x1ff;422entry->g_id = 63;423/*@(dec(A) + dec(B)*32) mod 512*/424} else if (phydm_acting_determine(dm, phydm_acting_as_ibss)) {425entry->p_aid = 0;426entry->g_id = 63;427} else {428entry->p_aid = sta->ra[5];429/*@BSSID[39:47]*/430entry->p_aid = (entry->p_aid << 1) | (sta->ra[4] >> 7);431entry->g_id = 0;432PHYDM_DBG(dm, DBG_TXBF,433"%s: P_AID addressed to AP=0x%X\n", __func__,434entry->p_aid);435}436437cp_mac_addr(entry->mac_addr, sta->ra);438entry->beamform_entry_cap = beamform_cap;439440entry->pre_log_seq = 0; /*@Modified by Jeffery @2015-04-13*/441entry->log_seq = 0; /*@Modified by Jeffery @2014-10-29*/442entry->log_retry_cnt = 0; /*@Modified by Jeffery @2014-10-29*/443entry->log_success = 0; /*@log_success is NOT needed to be accumulated, so LogSuccessCnt->log_success, 2015-04-13, Jeffery*/444entry->clock_reset_times = 0; /*@Modified by Jeffery @2015-04-13*/445446entry->num_of_sounding_dim = num_of_sounding_dim;447448if (beamform_cap & BEAMFORMEE_CAP_VHT_MU) {449dm->beamforming_info.beamformer_mu_cnt += 1;450entry->is_mu_ap = true;451entry->aid = sta->aid;452} else if (beamform_cap & (BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP_HT_EXPLICIT)) {453dm->beamforming_info.beamformer_su_cnt += 1;454entry->is_mu_ap = false;455}456457return entry;458} else459return NULL;460}461462#if 0463boolean464beamforming_remove_entry(465void *adapter,466u8 *RA,467u8 *idx468)469{470HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));471struct dm_struct *dm = &hal_data->DM_OutSrc;472473struct _RT_BEAMFORMER_ENTRY *bfer_entry = phydm_beamforming_get_bfer_entry_by_addr(dm, RA, idx);474struct _RT_BEAMFORMEE_ENTRY *entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, idx);475boolean ret = false;476477RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s Start!\n", __func__));478RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s, bfer_entry=0x%x\n", __func__, bfer_entry));479RT_DISP(FBEAM, FBEAM_FUN, ("[Beamforming]@%s, entry=0x%x\n", __func__, entry));480481if (entry != NULL) {482entry->is_used = false;483entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;484/*@entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;*/485entry->is_beamforming_in_progress = false;486ret = true;487}488if (bfer_entry != NULL) {489bfer_entry->is_used = false;490bfer_entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;491ret = true;492}493return ret;494}495#endif496497/* Used for beamforming_start_v1 */498void phydm_beamforming_ndpa_rate(499void *dm_void,500enum channel_width BW,501u8 rate)502{503u16 ndpa_rate = rate;504struct dm_struct *dm = (struct dm_struct *)dm_void;505506PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);507508if (ndpa_rate == 0) {509if (dm->rssi_min > 30) /* @link RSSI > 30% */510ndpa_rate = ODM_RATE24M;511else512ndpa_rate = ODM_RATE6M;513}514515if (ndpa_rate < ODM_RATEMCS0)516BW = (enum channel_width)CHANNEL_WIDTH_20;517518ndpa_rate = (ndpa_rate << 8) | BW;519hal_com_txbf_set(dm, TXBF_SET_SOUNDING_RATE, (u8 *)&ndpa_rate);520}521522/* Used for beamforming_start_sw and beamforming_start_fw */523void phydm_beamforming_dym_ndpa_rate(524void *dm_void)525{526u16 ndpa_rate = ODM_RATE6M, BW;527struct dm_struct *dm = (struct dm_struct *)dm_void;528529ndpa_rate = ODM_RATE6M;530BW = CHANNEL_WIDTH_20;531532ndpa_rate = ndpa_rate << 8 | BW;533hal_com_txbf_set(dm, TXBF_SET_SOUNDING_RATE, (u8 *)&ndpa_rate);534PHYDM_DBG(dm, DBG_TXBF, "%s End, NDPA rate = 0x%X\n", __func__,535ndpa_rate);536}537538/*@539* SW Sounding : SW Timer unit 1ms540* HW Timer unit (1/32000) s 32k is clock.541* FW Sounding : FW Timer unit 10ms542*/543void beamforming_dym_period(544void *dm_void,545u8 status)546{547u8 idx;548boolean is_change_period = false;549u16 sound_period_sw, sound_period_fw;550struct dm_struct *dm = (struct dm_struct *)dm_void;551552struct _RT_BEAMFORMEE_ENTRY *beamform_entry;553struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;554struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;555556struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];557558PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);559560/* @3 TODO per-client throughput caculation. */561562if ((*dm->current_tx_tp + *dm->current_rx_tp > 2) && (entry->log_status_fail_cnt <= 20 || status)) {563sound_period_sw = 40; /* @40ms */564sound_period_fw = 40; /* @From H2C cmd, unit = 10ms */565} else {566sound_period_sw = 4000; /* @4s */567sound_period_fw = 400;568}569PHYDM_DBG(dm, DBG_TXBF, "[%s]sound_period_sw=%d, sound_period_fw=%d\n",570__func__, sound_period_sw, sound_period_fw);571572for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {573beamform_entry = beam_info->beamformee_entry + idx;574575if (beamform_entry->default_csi_cnt > 20) {576/*@Modified by David*/577sound_period_sw = 4000;578sound_period_fw = 400;579}580581PHYDM_DBG(dm, DBG_TXBF, "[%s] period = %d\n", __func__,582sound_period_sw);583if ((beamform_entry->beamform_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) == 0)584continue;585586if (sound_info->sound_mode == SOUNDING_FW_VHT_TIMER || sound_info->sound_mode == SOUNDING_FW_HT_TIMER) {587if (beamform_entry->sound_period != sound_period_fw) {588beamform_entry->sound_period = sound_period_fw;589is_change_period = true; /*Only FW sounding need to send H2C packet to change sound period. */590}591} else if (beamform_entry->sound_period != sound_period_sw)592beamform_entry->sound_period = sound_period_sw;593}594595if (is_change_period)596hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);597}598599boolean600beamforming_send_ht_ndpa_packet(601void *dm_void,602u8 *RA,603enum channel_width BW,604u8 q_idx)605{606boolean ret = true;607struct dm_struct *dm = (struct dm_struct *)dm_void;608609if (q_idx == BEACON_QUEUE)610ret = send_fw_ht_ndpa_packet(dm, RA, BW);611else612ret = send_sw_ht_ndpa_packet(dm, RA, BW);613614return ret;615}616617boolean618beamforming_send_vht_ndpa_packet(619void *dm_void,620u8 *RA,621u16 AID,622enum channel_width BW,623u8 q_idx)624{625struct dm_struct *dm = (struct dm_struct *)dm_void;626struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;627boolean ret = true;628629hal_com_txbf_set(dm, TXBF_SET_GET_TX_RATE, NULL);630631if (beam_info->tx_bf_data_rate >= ODM_RATEVHTSS3MCS7 && beam_info->tx_bf_data_rate <= ODM_RATEVHTSS3MCS9 && !beam_info->snding3ss)632PHYDM_DBG(dm, DBG_TXBF, "@%s: 3SS VHT 789 don't sounding\n",633__func__);634635else {636if (q_idx == BEACON_QUEUE) /* Send to reserved page => FW NDPA */637ret = send_fw_vht_ndpa_packet(dm, RA, AID, BW);638else {639#ifdef SUPPORT_MU_BF640#if (SUPPORT_MU_BF == 1)641beam_info->is_mu_sounding = true;642ret = send_sw_vht_mu_ndpa_packet(dm, BW);643#else644beam_info->is_mu_sounding = false;645ret = send_sw_vht_ndpa_packet(dm, RA, AID, BW);646#endif647#else648beam_info->is_mu_sounding = false;649ret = send_sw_vht_ndpa_packet(dm, RA, AID, BW);650#endif651}652}653return ret;654}655656enum beamforming_notify_state657phydm_beamfomring_is_sounding(658void *dm_void,659struct _RT_BEAMFORMING_INFO *beam_info,660u8 *idx)661{662enum beamforming_notify_state is_sounding = BEAMFORMING_NOTIFY_NONE;663struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;664struct dm_struct *dm = (struct dm_struct *)dm_void;665u8 i;666667PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);668669/*@if(( Beamforming_GetBeamCap(beam_info) & BEAMFORMER_CAP) == 0)*/670/*@is_sounding = BEAMFORMING_NOTIFY_RESET;*/671if (beam_oid_info.sound_oid_mode == sounding_stop_all_timer) {672is_sounding = BEAMFORMING_NOTIFY_RESET;673goto out;674}675676for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {677PHYDM_DBG(dm, DBG_TXBF,678"@%s: BFee Entry %d is_used=%d, is_sound=%d\n",679__func__, i, beam_info->beamformee_entry[i].is_used,680beam_info->beamformee_entry[i].is_sound);681if (beam_info->beamformee_entry[i].is_used && !beam_info->beamformee_entry[i].is_sound) {682PHYDM_DBG(dm, DBG_TXBF, "%s: Add BFee entry %d\n",683__func__, i);684*idx = i;685if (beam_info->beamformee_entry[i].is_mu_sta)686is_sounding = BEAMFORMEE_NOTIFY_ADD_MU;687else688is_sounding = BEAMFORMEE_NOTIFY_ADD_SU;689}690691if (!beam_info->beamformee_entry[i].is_used && beam_info->beamformee_entry[i].is_sound) {692PHYDM_DBG(dm, DBG_TXBF, "%s: Delete BFee entry %d\n",693__func__, i);694*idx = i;695if (beam_info->beamformee_entry[i].is_mu_sta)696is_sounding = BEAMFORMEE_NOTIFY_DELETE_MU;697else698is_sounding = BEAMFORMEE_NOTIFY_DELETE_SU;699}700}701702out:703PHYDM_DBG(dm, DBG_TXBF, "%s End, is_sounding = %d\n", __func__,704is_sounding);705return is_sounding;706}707708/* This function is unused */709u8 phydm_beamforming_sounding_idx(710void *dm_void,711struct _RT_BEAMFORMING_INFO *beam_info)712{713u8 idx = 0;714struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;715struct dm_struct *dm = (struct dm_struct *)dm_void;716717PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);718719if (beam_oid_info.sound_oid_mode == SOUNDING_SW_HT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_SW_VHT_TIMER ||720beam_oid_info.sound_oid_mode == SOUNDING_HW_HT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_HW_VHT_TIMER)721idx = beam_oid_info.sound_oid_idx;722else {723u8 i;724for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {725if (beam_info->beamformee_entry[i].is_used && !beam_info->beamformee_entry[i].is_sound) {726idx = i;727break;728}729}730}731732return idx;733}734735enum sounding_mode736phydm_beamforming_sounding_mode(737void *dm_void,738struct _RT_BEAMFORMING_INFO *beam_info,739u8 idx)740{741struct dm_struct *dm = (struct dm_struct *)dm_void;742u8 support_interface = dm->support_interface;743744struct _RT_BEAMFORMEE_ENTRY beam_entry = beam_info->beamformee_entry[idx];745struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;746enum sounding_mode mode = beam_oid_info.sound_oid_mode;747748if (beam_oid_info.sound_oid_mode == SOUNDING_SW_VHT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_HW_VHT_TIMER) {749if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)750mode = beam_oid_info.sound_oid_mode;751else752mode = sounding_stop_all_timer;753} else if (beam_oid_info.sound_oid_mode == SOUNDING_SW_HT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_HW_HT_TIMER) {754if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)755mode = beam_oid_info.sound_oid_mode;756else757mode = sounding_stop_all_timer;758} else if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_VHT_SU) {759if (support_interface == ODM_ITRF_USB && !(dm->support_ic_type & (ODM_RTL8814A | ODM_RTL8822B)))760mode = SOUNDING_FW_VHT_TIMER;761else762mode = SOUNDING_SW_VHT_TIMER;763} else if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT) {764if (support_interface == ODM_ITRF_USB && !(dm->support_ic_type & (ODM_RTL8814A | ODM_RTL8822B)))765mode = SOUNDING_FW_HT_TIMER;766else767mode = SOUNDING_SW_HT_TIMER;768} else769mode = sounding_stop_all_timer;770771PHYDM_DBG(dm, DBG_TXBF, "[%s] support_interface=%d, mode=%d\n",772__func__, support_interface, mode);773774return mode;775}776777u16 phydm_beamforming_sounding_time(778void *dm_void,779struct _RT_BEAMFORMING_INFO *beam_info,780enum sounding_mode mode,781u8 idx)782{783u16 sounding_time = 0xffff;784struct _RT_BEAMFORMEE_ENTRY beam_entry = beam_info->beamformee_entry[idx];785struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;786struct dm_struct *dm = (struct dm_struct *)dm_void;787788PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);789790if (mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_HW_VHT_TIMER)791sounding_time = beam_oid_info.sound_oid_period * 32;792else if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_SW_VHT_TIMER)793/*@Modified by David*/794sounding_time = beam_entry.sound_period; /*@beam_oid_info.sound_oid_period;*/795else796sounding_time = beam_entry.sound_period;797798return sounding_time;799}800801enum channel_width802phydm_beamforming_sounding_bw(803void *dm_void,804struct _RT_BEAMFORMING_INFO *beam_info,805enum sounding_mode mode,806u8 idx)807{808enum channel_width sounding_bw = CHANNEL_WIDTH_20;809struct _RT_BEAMFORMEE_ENTRY beam_entry = beam_info->beamformee_entry[idx];810struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;811struct dm_struct *dm = (struct dm_struct *)dm_void;812813if (mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_HW_VHT_TIMER)814sounding_bw = beam_oid_info.sound_oid_bw;815else if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_SW_VHT_TIMER)816/*@Modified by David*/817sounding_bw = beam_entry.sound_bw; /*@beam_oid_info.sound_oid_bw;*/818else819sounding_bw = beam_entry.sound_bw;820821PHYDM_DBG(dm, DBG_TXBF, "%s, sounding_bw=0x%X\n", __func__,822sounding_bw);823824return sounding_bw;825}826827boolean828phydm_beamforming_select_beam_entry(829void *dm_void,830struct _RT_BEAMFORMING_INFO *beam_info)831{832struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;833struct dm_struct *dm = (struct dm_struct *)dm_void;834835/*@entry.is_sound is different between first and latter NDPA, and should not be used as BFee entry selection*/836/*@BTW, latter modification should sync to the selection mechanism of AP/ADSL instead of the fixed sound_idx.*/837sound_info->sound_idx = phydm_beamforming_sounding_idx(dm, beam_info);838/*sound_info->sound_idx = 0;*/839840if (sound_info->sound_idx < BEAMFORMEE_ENTRY_NUM)841sound_info->sound_mode = phydm_beamforming_sounding_mode(dm, beam_info, sound_info->sound_idx);842else843sound_info->sound_mode = sounding_stop_all_timer;844845if (sounding_stop_all_timer == sound_info->sound_mode) {846PHYDM_DBG(dm, DBG_TXBF,847"[%s] Return because of sounding_stop_all_timer\n",848__func__);849return false;850} else {851sound_info->sound_bw = phydm_beamforming_sounding_bw(dm, beam_info, sound_info->sound_mode, sound_info->sound_idx);852sound_info->sound_period = phydm_beamforming_sounding_time(dm, beam_info, sound_info->sound_mode, sound_info->sound_idx);853return true;854}855}856857/*SU BFee Entry Only*/858boolean859phydm_beamforming_start_period(860void *dm_void)861{862struct dm_struct *dm = (struct dm_struct *)dm_void;863boolean ret = true;864struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;865struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;866867phydm_beamforming_dym_ndpa_rate(dm);868869phydm_beamforming_select_beam_entry(dm, beam_info); /* @Modified */870871if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)872odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);873else if (sound_info->sound_mode == SOUNDING_HW_VHT_TIMER || sound_info->sound_mode == SOUNDING_HW_HT_TIMER ||874sound_info->sound_mode == SOUNDING_AUTO_VHT_TIMER || sound_info->sound_mode == SOUNDING_AUTO_HT_TIMER) {875HAL_HW_TIMER_TYPE timer_type = HAL_TIMER_TXBF;876u32 val = (sound_info->sound_period | (timer_type << 16));877878/* @HW timer stop: All IC has the same setting */879phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_STOP, (u8 *)(&timer_type));880/* odm_write_1byte(dm, 0x15F, 0); */881/* @HW timer init: All IC has the same setting, but 92E & 8812A only write 2 bytes */882phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_INIT, (u8 *)(&val));883/* odm_write_1byte(dm, 0x164, 1); */884/* odm_write_4byte(dm, 0x15C, val); */885/* @HW timer start: All IC has the same setting */886phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_START, (u8 *)(&timer_type));887/* odm_write_1byte(dm, 0x15F, 0x5); */888} else if (sound_info->sound_mode == SOUNDING_FW_VHT_TIMER || sound_info->sound_mode == SOUNDING_FW_HT_TIMER)889ret = beamforming_start_fw(dm, sound_info->sound_idx);890else891ret = false;892893PHYDM_DBG(dm, DBG_TXBF,894"[%s] sound_idx=%d, sound_mode=%d, sound_bw=%d, sound_period=%d\n",895__func__, sound_info->sound_idx, sound_info->sound_mode,896sound_info->sound_bw, sound_info->sound_period);897898return ret;899}900901/* Used after beamforming_leave, and will clear the setting of the "already deleted" entry902*SU BFee Entry Only*/903void phydm_beamforming_end_period_sw(904void *dm_void)905{906struct dm_struct *dm = (struct dm_struct *)dm_void;907/*void *adapter = dm->adapter;*/908struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;909struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;910911HAL_HW_TIMER_TYPE timer_type = HAL_TIMER_TXBF;912913PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);914915if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)916odm_cancel_timer(dm, &beam_info->beamforming_timer);917else if (sound_info->sound_mode == SOUNDING_HW_VHT_TIMER || sound_info->sound_mode == SOUNDING_HW_HT_TIMER ||918sound_info->sound_mode == SOUNDING_AUTO_VHT_TIMER || sound_info->sound_mode == SOUNDING_AUTO_HT_TIMER)919/*@HW timer stop: All IC has the same setting*/920phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_STOP, (u8 *)(&timer_type));921/*odm_write_1byte(dm, 0x15F, 0);*/922}923924void phydm_beamforming_end_period_fw(925void *dm_void)926{927struct dm_struct *dm = (struct dm_struct *)dm_void;928u8 idx = 0;929930hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);931PHYDM_DBG(dm, DBG_TXBF, "[%s]\n", __func__);932}933934/*SU BFee Entry Only*/935void phydm_beamforming_clear_entry_sw(936void *dm_void,937boolean is_delete,938u8 delete_idx)939{940u8 idx = 0;941struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;942struct dm_struct *dm = (struct dm_struct *)dm_void;943struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;944945if (is_delete) {946if (delete_idx < BEAMFORMEE_ENTRY_NUM) {947beamform_entry = beam_info->beamformee_entry + delete_idx;948if (!(!beamform_entry->is_used && beamform_entry->is_sound)) {949PHYDM_DBG(dm, DBG_TXBF,950"[%s] SW delete_idx is wrong!!!!!\n",951__func__);952return;953}954}955956PHYDM_DBG(dm, DBG_TXBF, "[%s] SW delete BFee entry %d\n",957__func__, delete_idx);958if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSING) {959beamform_entry->is_beamforming_in_progress = false;960beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;961} else if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSED) {962beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;963hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS, (u8 *)&delete_idx);964}965beamform_entry->is_sound = false;966return;967}968969for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {970beamform_entry = beam_info->beamformee_entry + idx;971972/*Used after is_sounding=RESET, and will clear the setting of "ever sounded" entry, which is not necessarily be deleted.*/973/*This function is mainly used in case "beam_oid_info.sound_oid_mode == sounding_stop_all_timer".*/974/*@However, setting oid doesn't delete entries (is_used is still true), new entries may fail to be added in.*/975976if (!beamform_entry->is_sound)977continue;978979PHYDM_DBG(dm, DBG_TXBF, "[%s] SW reset BFee entry %d\n",980__func__, idx);981/*@982* If End procedure is983* 1. Between (Send NDPA, C2H packet return), reset state to initialized.984* After C2H packet return , status bit will be set to zero.985*986* 2. After C2H packet, then reset state to initialized and clear status bit.987*/988989if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSING)990phydm_beamforming_end_sw(dm, 0);991else if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSED) {992beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;993hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS, (u8 *)&idx);994}995996beamform_entry->is_sound = false;997}998}9991000void phydm_beamforming_clear_entry_fw(1001void *dm_void,1002boolean is_delete,1003u8 delete_idx)1004{1005u8 idx = 0;1006struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;1007struct dm_struct *dm = (struct dm_struct *)dm_void;1008struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;10091010if (is_delete) {1011if (delete_idx < BEAMFORMEE_ENTRY_NUM) {1012beamform_entry = beam_info->beamformee_entry + delete_idx;10131014if (!(!beamform_entry->is_used && beamform_entry->is_sound)) {1015PHYDM_DBG(dm, DBG_TXBF,1016"[%s] FW delete_idx is wrong!!!!!\n",1017__func__);1018return;1019}1020}1021PHYDM_DBG(dm, DBG_TXBF, "%s: FW delete BFee entry %d\n",1022__func__, delete_idx);1023beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;1024beamform_entry->is_sound = false;1025} else {1026for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {1027beamform_entry = beam_info->beamformee_entry + idx;10281029/*Used after is_sounding=RESET, and will clear the setting of "ever sounded" entry, which is not necessarily be deleted.*/1030/*This function is mainly used in case "beam_oid_info.sound_oid_mode == sounding_stop_all_timer".*/1031/*@However, setting oid doesn't delete entries (is_used is still true), new entries may fail to be added in.*/10321033if (beamform_entry->is_sound) {1034PHYDM_DBG(dm, DBG_TXBF,1035"[%s]FW reset BFee entry %d\n",1036__func__, idx);1037/*@1038* If End procedure is1039* 1. Between (Send NDPA, C2H packet return), reset state to initialized.1040* After C2H packet return , status bit will be set to zero.1041*1042* 2. After C2H packet, then reset state to initialized and clear status bit.1043*/10441045beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;1046beamform_entry->is_sound = false;1047}1048}1049}1050}10511052/*@1053* Called :1054* 1. Add and delete entry : beamforming_enter/beamforming_leave1055* 2. FW trigger : Beamforming_SetTxBFen1056* 3. Set OID_RT_BEAMFORMING_PERIOD : beamforming_control_v21057*/1058void phydm_beamforming_notify(1059void *dm_void)1060{1061u8 idx = BEAMFORMEE_ENTRY_NUM;1062enum beamforming_notify_state is_sounding = BEAMFORMING_NOTIFY_NONE;1063struct dm_struct *dm = (struct dm_struct *)dm_void;1064struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1065struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;10661067PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);10681069is_sounding = phydm_beamfomring_is_sounding(dm, beam_info, &idx);10701071PHYDM_DBG(dm, DBG_TXBF, "%s, Before notify, is_sounding=%d, idx=%d\n",1072__func__, is_sounding, idx);1073PHYDM_DBG(dm, DBG_TXBF, "%s: beam_info->beamformee_su_cnt = %d\n",1074__func__, beam_info->beamformee_su_cnt);10751076switch (is_sounding) {1077case BEAMFORMEE_NOTIFY_ADD_SU:1078PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_ADD_SU\n",1079__func__);1080phydm_beamforming_start_period(dm);1081break;10821083case BEAMFORMEE_NOTIFY_DELETE_SU:1084PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_DELETE_SU\n",1085__func__);1086if (sound_info->sound_mode == SOUNDING_FW_HT_TIMER || sound_info->sound_mode == SOUNDING_FW_VHT_TIMER) {1087phydm_beamforming_clear_entry_fw(dm, true, idx);1088if (beam_info->beamformee_su_cnt == 0) { /* @For 2->1 entry, we should not cancel SW timer */1089phydm_beamforming_end_period_fw(dm);1090PHYDM_DBG(dm, DBG_TXBF, "%s: No BFee left\n",1091__func__);1092}1093} else {1094phydm_beamforming_clear_entry_sw(dm, true, idx);1095if (beam_info->beamformee_su_cnt == 0) { /* @For 2->1 entry, we should not cancel SW timer */1096phydm_beamforming_end_period_sw(dm);1097PHYDM_DBG(dm, DBG_TXBF, "%s: No BFee left\n",1098__func__);1099}1100}1101break;11021103case BEAMFORMEE_NOTIFY_ADD_MU:1104PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_ADD_MU\n",1105__func__);1106if (beam_info->beamformee_mu_cnt == 2) {1107/*@if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)1108odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);*/1109odm_set_timer(dm, &beam_info->beamforming_timer, 1000); /*@Do MU sounding every 1sec*/1110} else1111PHYDM_DBG(dm, DBG_TXBF,1112"%s: Less or larger than 2 MU STAs, not to set timer\n",1113__func__);1114break;11151116case BEAMFORMEE_NOTIFY_DELETE_MU:1117PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_DELETE_MU\n",1118__func__);1119if (beam_info->beamformee_mu_cnt == 1) {1120/*@if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)*/ {1121odm_cancel_timer(dm, &beam_info->beamforming_timer);1122PHYDM_DBG(dm, DBG_TXBF,1123"%s: Less than 2 MU STAs, stop sounding\n",1124__func__);1125}1126}1127break;11281129case BEAMFORMING_NOTIFY_RESET:1130if (sound_info->sound_mode == SOUNDING_FW_HT_TIMER || sound_info->sound_mode == SOUNDING_FW_VHT_TIMER) {1131phydm_beamforming_clear_entry_fw(dm, false, idx);1132phydm_beamforming_end_period_fw(dm);1133} else {1134phydm_beamforming_clear_entry_sw(dm, false, idx);1135phydm_beamforming_end_period_sw(dm);1136}11371138break;11391140default:1141break;1142}1143}11441145boolean1146beamforming_init_entry(void *dm_void, u16 sta_idx, u8 *bfer_bfee_idx,1147u8 *my_mac_addr)1148{1149struct dm_struct *dm = (struct dm_struct *)dm_void;1150struct cmn_sta_info *cmn_sta = dm->phydm_sta_info[sta_idx];1151struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;1152struct _RT_BEAMFORMER_ENTRY *beamformer_entry = NULL;1153struct _RT_BEAMFORM_STAINFO *sta = NULL;1154enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE;1155u8 bfer_idx = 0xF, bfee_idx = 0xF;1156u8 num_of_sounding_dim = 0, comp_steering_num_of_bfer = 0;11571158if (!is_sta_active(cmn_sta)) {1159PHYDM_DBG(dm, DBG_TXBF, "%s => sta_info(mac_id:%d) failed\n",1160__func__, sta_idx);1161#if (DM_ODM_SUPPORT_TYPE == ODM_CE)1162rtw_warn_on(1);1163#endif1164return false;1165}11661167sta = phydm_sta_info_init(dm, sta_idx, my_mac_addr);1168/*The current setting does not support Beaforming*/1169if (BEAMFORMING_CAP_NONE == sta->ht_beamform_cap && BEAMFORMING_CAP_NONE == sta->vht_beamform_cap) {1170PHYDM_DBG(dm, DBG_TXBF,1171"The configuration disabled Beamforming! Skip...\n");1172return false;1173}11741175if (!(cmn_sta->support_wireless_set & (WIRELESS_VHT | WIRELESS_HT)))1176return false;1177else {1178if (cmn_sta->support_wireless_set & WIRELESS_HT) { /*@HT*/1179if (TEST_FLAG(sta->cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { /*We are Beamformee because the STA is Beamformer*/1180beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP_HT_EXPLICIT);1181num_of_sounding_dim = (sta->cur_beamform & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6;1182}1183/*We are Beamformer because the STA is Beamformee*/1184if (TEST_FLAG(sta->cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE) ||1185TEST_FLAG(sta->ht_beamform_cap, BEAMFORMING_HT_BEAMFORMER_TEST)) {1186beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT);1187comp_steering_num_of_bfer = (sta->cur_beamform & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4;1188}1189PHYDM_DBG(dm, DBG_TXBF,1190"[%s] HT cur_beamform=0x%X, beamform_cap=0x%X\n",1191__func__, sta->cur_beamform, beamform_cap);1192PHYDM_DBG(dm, DBG_TXBF,1193"[%s] HT num_of_sounding_dim=%d, comp_steering_num_of_bfer=%d\n",1194__func__, num_of_sounding_dim,1195comp_steering_num_of_bfer);1196}1197#if (ODM_IC_11AC_SERIES_SUPPORT == 1)1198if (cmn_sta->support_wireless_set & WIRELESS_VHT) { /*VHT*/11991200/* We are Beamformee because the STA is SU Beamformer*/1201if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {1202beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP_VHT_SU);1203num_of_sounding_dim = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;1204}1205/* We are Beamformer because the STA is SU Beamformee*/1206if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) ||1207TEST_FLAG(sta->vht_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_TEST)) {1208beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP_VHT_SU);1209comp_steering_num_of_bfer = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;1210}1211/* We are Beamformee because the STA is MU Beamformer*/1212if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {1213beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP_VHT_MU);1214num_of_sounding_dim = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;1215}1216/* We are Beamformer because the STA is MU Beamformee*/1217if (phydm_acting_determine(dm, phydm_acting_as_ap)) { /* Only AP mode supports to act an MU beamformer */1218if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE) ||1219TEST_FLAG(sta->vht_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_TEST)) {1220beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP_VHT_MU);1221comp_steering_num_of_bfer = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;1222}1223}1224PHYDM_DBG(dm, DBG_TXBF,1225"[%s]VHT cur_beamform_vht=0x%X, beamform_cap=0x%X\n",1226__func__, sta->cur_beamform_vht,1227beamform_cap);1228PHYDM_DBG(dm, DBG_TXBF,1229"[%s]VHT num_of_sounding_dim=0x%X, comp_steering_num_of_bfer=0x%X\n",1230__func__, num_of_sounding_dim,1231comp_steering_num_of_bfer);1232}1233#endif1234}12351236if (beamform_cap == BEAMFORMING_CAP_NONE)1237return false;12381239PHYDM_DBG(dm, DBG_TXBF, "[%s] Self BF Entry Cap = 0x%02X\n", __func__,1240beamform_cap);12411242/*We are BFee, so the entry is BFer*/1243if (beamform_cap & (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP_HT_EXPLICIT)) {1244beamformer_entry = phydm_beamforming_get_bfer_entry_by_addr(dm, sta->ra, &bfer_idx);12451246if (beamformer_entry == NULL) {1247beamformer_entry = beamforming_add_bfer_entry(dm, sta, beamform_cap, num_of_sounding_dim, &bfer_idx);1248if (beamformer_entry == NULL)1249PHYDM_DBG(dm, DBG_TXBF,1250"[%s]Not enough BFer entry!!!!!\n",1251__func__);1252}1253}12541255/*We are BFer, so the entry is BFee*/1256if (beamform_cap & (BEAMFORMER_CAP_VHT_MU | BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP_HT_EXPLICIT)) {1257beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, sta->ra, &bfee_idx);12581259/*@if BFeeIdx = 0xF, that represent for no matched MACID among all linked entrys */1260PHYDM_DBG(dm, DBG_TXBF, "[%s] Get BFee entry 0x%X by address\n",1261__func__, bfee_idx);1262if (beamform_entry == NULL) {1263beamform_entry = beamforming_add_bfee_entry(dm, sta, beamform_cap, num_of_sounding_dim, comp_steering_num_of_bfer, &bfee_idx);1264PHYDM_DBG(dm, DBG_TXBF,1265"[%s]: sta->AID=%d, sta->mac_id=%d\n",1266__func__, sta->aid, sta->mac_id);12671268PHYDM_DBG(dm, DBG_TXBF, "[%s]: Add BFee entry %d\n",1269__func__, bfee_idx);12701271if (beamform_entry == NULL)1272return false;1273else1274beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;1275} else {1276/*@Entry has been created. If entry is initialing or progressing then errors occur.*/1277if (beamform_entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED &&1278beamform_entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED)1279return false;1280else1281beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;1282}1283beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;1284phydm_sta_info_update(dm, sta_idx, beamform_entry);1285}12861287*bfer_bfee_idx = (bfer_idx << 4) | bfee_idx;1288PHYDM_DBG(dm, DBG_TXBF,1289"[%s] End: bfer_idx=0x%X, bfee_idx=0x%X, bfer_bfee_idx=0x%X\n",1290__func__, bfer_idx, bfee_idx, *bfer_bfee_idx);12911292return true;1293}12941295void beamforming_deinit_entry(1296void *dm_void,1297u8 *RA)1298{1299struct dm_struct *dm = (struct dm_struct *)dm_void;1300u8 idx = 0;13011302struct _RT_BEAMFORMER_ENTRY *bfer_entry = phydm_beamforming_get_bfer_entry_by_addr(dm, RA, &idx);1303struct _RT_BEAMFORMEE_ENTRY *bfee_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);1304boolean ret = false;13051306PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);13071308if (bfee_entry != NULL) {1309PHYDM_DBG(dm, DBG_TXBF, "%s, bfee_entry\n", __func__);1310bfee_entry->is_used = false;1311bfee_entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;1312bfee_entry->is_beamforming_in_progress = false;1313if (bfee_entry->is_mu_sta) {1314dm->beamforming_info.beamformee_mu_cnt -= 1;1315dm->beamforming_info.first_mu_bfee_index = phydm_beamforming_get_first_mu_bfee_entry_idx(dm);1316} else1317dm->beamforming_info.beamformee_su_cnt -= 1;1318ret = true;1319}13201321if (bfer_entry != NULL) {1322PHYDM_DBG(dm, DBG_TXBF, "%s, bfer_entry\n", __func__);1323bfer_entry->is_used = false;1324bfer_entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;1325if (bfer_entry->is_mu_ap)1326dm->beamforming_info.beamformer_mu_cnt -= 1;1327else1328dm->beamforming_info.beamformer_su_cnt -= 1;1329ret = true;1330}13311332if (ret == true)1333hal_com_txbf_set(dm, TXBF_SET_SOUNDING_LEAVE, (u8 *)&idx);13341335PHYDM_DBG(dm, DBG_TXBF, "%s End, idx = 0x%X\n", __func__, idx);1336}13371338boolean1339beamforming_start_v1(1340void *dm_void,1341u8 *RA,1342boolean mode,1343enum channel_width BW,1344u8 rate)1345{1346struct dm_struct *dm = (struct dm_struct *)dm_void;1347u8 idx = 0;1348struct _RT_BEAMFORMEE_ENTRY *entry;1349boolean ret = true;1350struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;13511352entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);13531354if (entry->is_used == false) {1355entry->is_beamforming_in_progress = false;1356return false;1357} else {1358if (entry->is_beamforming_in_progress)1359return false;13601361entry->is_beamforming_in_progress = true;13621363if (mode == 1) {1364if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) {1365entry->is_beamforming_in_progress = false;1366return false;1367}1368} else if (mode == 0) {1369if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)) {1370entry->is_beamforming_in_progress = false;1371return false;1372}1373}13741375if (entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {1376entry->is_beamforming_in_progress = false;1377return false;1378} else {1379entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;1380entry->is_sound = true;1381}1382}13831384entry->sound_bw = BW;1385beam_info->beamformee_cur_idx = idx;1386phydm_beamforming_ndpa_rate(dm, BW, rate);1387hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS, (u8 *)&idx);13881389if (mode == 1)1390ret = beamforming_send_ht_ndpa_packet(dm, RA, BW, NORMAL_QUEUE);1391else1392ret = beamforming_send_vht_ndpa_packet(dm, RA, entry->aid, BW, NORMAL_QUEUE);13931394if (ret == false) {1395beamforming_leave(dm, RA);1396entry->is_beamforming_in_progress = false;1397return false;1398}13991400PHYDM_DBG(dm, DBG_TXBF, "%s idx %d\n", __func__, idx);1401return true;1402}14031404boolean1405beamforming_start_sw(1406void *dm_void,1407u8 idx,1408u8 mode,1409enum channel_width BW)1410{1411u8 *ra = NULL;1412struct dm_struct *dm = (struct dm_struct *)dm_void;1413struct _RT_BEAMFORMEE_ENTRY *entry;1414boolean ret = true;1415struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1416#ifdef SUPPORT_MU_BF1417#if (SUPPORT_MU_BF == 1)1418u8 i, poll_sta_cnt = 0;1419boolean is_get_first_bfee = false;1420#endif1421#endif14221423if (beam_info->is_mu_sounding) {1424beam_info->is_mu_sounding_in_progress = true;1425entry = &beam_info->beamformee_entry[idx];1426ra = entry->mac_addr;14271428} else {1429entry = &beam_info->beamformee_entry[idx];14301431if (entry->is_used == false) {1432PHYDM_DBG(dm, DBG_TXBF,1433"Skip Beamforming, no entry for idx =%d\n",1434idx);1435entry->is_beamforming_in_progress = false;1436return false;1437}14381439if (entry->is_beamforming_in_progress) {1440PHYDM_DBG(dm, DBG_TXBF,1441"is_beamforming_in_progress, skip...\n");1442return false;1443}14441445entry->is_beamforming_in_progress = true;1446ra = entry->mac_addr;14471448if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_AUTO_HT_TIMER) {1449if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) {1450entry->is_beamforming_in_progress = false;1451PHYDM_DBG(dm, DBG_TXBF,1452"%s Return by not support BEAMFORMER_CAP_HT_EXPLICIT <==\n",1453__func__);1454return false;1455}1456} else if (mode == SOUNDING_SW_VHT_TIMER || mode == SOUNDING_HW_VHT_TIMER || mode == SOUNDING_AUTO_VHT_TIMER) {1457if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)) {1458entry->is_beamforming_in_progress = false;1459PHYDM_DBG(dm, DBG_TXBF,1460"%s Return by not support BEAMFORMER_CAP_VHT_SU <==\n",1461__func__);1462return false;1463}1464}1465if (entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {1466entry->is_beamforming_in_progress = false;1467PHYDM_DBG(dm, DBG_TXBF,1468"%s Return by incorrect beamform_entry_state(%d) <==\n",1469__func__, entry->beamform_entry_state);1470return false;1471} else {1472entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;1473entry->is_sound = true;1474}14751476beam_info->beamformee_cur_idx = idx;1477}14781479/*@2014.12.22 Luke: Need to be checked*/1480/*@GET_TXBF_INFO(adapter)->fTxbfSet(adapter, TXBF_SET_SOUNDING_STATUS, (u8*)&idx);*/14811482if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_AUTO_HT_TIMER)1483ret = beamforming_send_ht_ndpa_packet(dm, ra, BW, NORMAL_QUEUE);1484else1485ret = beamforming_send_vht_ndpa_packet(dm, ra, entry->aid, BW, NORMAL_QUEUE);14861487if (ret == false) {1488beamforming_leave(dm, ra);1489entry->is_beamforming_in_progress = false;1490return false;1491}14921493/*@--------------------------1494* Send BF Report Poll for MU BF1495--------------------------*/1496#ifdef SUPPORT_MU_BF1497#if (SUPPORT_MU_BF == 1)1498if (beam_info->beamformee_mu_cnt <= 1)1499goto out;15001501/* @More than 1 MU STA*/1502for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {1503entry = &beam_info->beamformee_entry[i];1504if (!entry->is_mu_sta)1505continue;15061507if (!is_get_first_bfee) {1508is_get_first_bfee = true;1509continue;1510}15111512poll_sta_cnt++;1513if (poll_sta_cnt == (beam_info->beamformee_mu_cnt - 1)) /* The last STA*/1514send_sw_vht_bf_report_poll(dm, entry->mac_addr, true);1515else1516send_sw_vht_bf_report_poll(dm, entry->mac_addr, false);1517}1518out:1519#endif1520#endif1521return true;1522}15231524boolean1525beamforming_start_fw(1526void *dm_void,1527u8 idx)1528{1529struct dm_struct *dm = (struct dm_struct *)dm_void;1530struct _RT_BEAMFORMEE_ENTRY *entry;1531struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;15321533entry = &beam_info->beamformee_entry[idx];1534if (entry->is_used == false) {1535PHYDM_DBG(dm, DBG_TXBF,1536"Skip Beamforming, no entry for idx =%d\n", idx);1537return false;1538}15391540entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;1541entry->is_sound = true;1542hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);15431544PHYDM_DBG(dm, DBG_TXBF, "[%s] End, idx=0x%X\n", __func__, idx);1545return true;1546}15471548void beamforming_check_sounding_success(1549void *dm_void,1550boolean status)1551{1552struct dm_struct *dm = (struct dm_struct *)dm_void;1553struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1554struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];15551556PHYDM_DBG(dm, DBG_TXBF, "[David]@%s Start!\n", __func__);15571558if (status == 1) {1559if (entry->log_status_fail_cnt == 21)1560beamforming_dym_period(dm, status);1561entry->log_status_fail_cnt = 0;1562} else if (entry->log_status_fail_cnt <= 20) {1563entry->log_status_fail_cnt++;1564PHYDM_DBG(dm, DBG_TXBF, "%s log_status_fail_cnt %d\n", __func__,1565entry->log_status_fail_cnt);1566}1567if (entry->log_status_fail_cnt > 20) {1568entry->log_status_fail_cnt = 21;1569PHYDM_DBG(dm, DBG_TXBF,1570"%s log_status_fail_cnt > 20, Stop SOUNDING\n",1571__func__);1572beamforming_dym_period(dm, status);1573}1574}15751576void phydm_beamforming_end_sw(1577void *dm_void,1578boolean status)1579{1580struct dm_struct *dm = (struct dm_struct *)dm_void;1581struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1582struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];15831584if (beam_info->is_mu_sounding) {1585PHYDM_DBG(dm, DBG_TXBF, "%s: MU sounding done\n", __func__);1586beam_info->is_mu_sounding_in_progress = false;1587hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS,1588(u8 *)&beam_info->beamformee_cur_idx);1589} else {1590if (entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSING) {1591PHYDM_DBG(dm, DBG_TXBF, "[%s] BeamformStatus %d\n",1592__func__, entry->beamform_entry_state);1593return;1594}15951596if (beam_info->tx_bf_data_rate >= ODM_RATEVHTSS3MCS7 && beam_info->tx_bf_data_rate <= ODM_RATEVHTSS3MCS9 && !beam_info->snding3ss) {1597PHYDM_DBG(dm, DBG_TXBF,1598"[%s] VHT3SS 7,8,9, do not apply V matrix.\n",1599__func__);1600entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;1601hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS,1602(u8 *)&beam_info->beamformee_cur_idx);1603} else if (status == 1) {1604entry->log_status_fail_cnt = 0;1605entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSED;1606hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS,1607(u8 *)&beam_info->beamformee_cur_idx);1608} else {1609entry->log_status_fail_cnt++;1610entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;1611hal_com_txbf_set(dm, TXBF_SET_TX_PATH_RESET,1612(u8 *)&beam_info->beamformee_cur_idx);1613PHYDM_DBG(dm, DBG_TXBF, "[%s] log_status_fail_cnt %d\n",1614__func__, entry->log_status_fail_cnt);1615}16161617if (entry->log_status_fail_cnt > 50) {1618PHYDM_DBG(dm, DBG_TXBF,1619"%s log_status_fail_cnt > 50, Stop SOUNDING\n",1620__func__);1621entry->is_sound = false;1622beamforming_deinit_entry(dm, entry->mac_addr);16231624/*@Modified by David - Every action of deleting entry should follow by Notify*/1625phydm_beamforming_notify(dm);1626}16271628entry->is_beamforming_in_progress = false;1629}1630PHYDM_DBG(dm, DBG_TXBF, "%s: status=%d\n", __func__, status);1631}16321633void beamforming_timer_callback(1634#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1635void *dm_void1636#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)1637void *context1638#endif1639)1640{1641#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1642struct dm_struct *dm = (struct dm_struct *)dm_void;1643#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)1644void *adapter = (void *)context;1645PHAL_DATA_TYPE hal_data = GET_HAL_DATA(((PADAPTER)adapter));1646struct dm_struct *dm = &hal_data->odmpriv;1647#endif1648boolean ret = false;1649struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);1650struct _RT_BEAMFORMEE_ENTRY *entry = &(beam_info->beamformee_entry[beam_info->beamformee_cur_idx]);1651struct _RT_SOUNDING_INFO *sound_info = &(beam_info->sounding_info);1652boolean is_beamforming_in_progress;16531654PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);16551656if (beam_info->is_mu_sounding)1657is_beamforming_in_progress = beam_info->is_mu_sounding_in_progress;1658else1659is_beamforming_in_progress = entry->is_beamforming_in_progress;16601661if (is_beamforming_in_progress) {1662PHYDM_DBG(dm, DBG_TXBF,1663"is_beamforming_in_progress, reset it\n");1664phydm_beamforming_end_sw(dm, 0);1665}16661667ret = phydm_beamforming_select_beam_entry(dm, beam_info);1668#if (SUPPORT_MU_BF == 1)1669if (ret && beam_info->beamformee_mu_cnt > 1)1670ret = 1;1671else1672ret = 0;1673#endif1674if (ret)1675ret = beamforming_start_sw(dm, sound_info->sound_idx, sound_info->sound_mode, sound_info->sound_bw);1676else1677PHYDM_DBG(dm, DBG_TXBF,1678"%s, Error value return from BeamformingStart_V2\n",1679__func__);16801681if (beam_info->beamformee_su_cnt != 0 || beam_info->beamformee_mu_cnt > 1) {1682if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)1683odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);1684else {1685u32 val = (sound_info->sound_period << 16) | HAL_TIMER_TXBF;1686phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_RESTART, (u8 *)(&val));1687}1688}1689}16901691void beamforming_sw_timer_callback(1692#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1693struct phydm_timer_list *timer1694#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)1695void *function_context1696#endif1697)1698{1699#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1700void *adapter = (void *)timer->Adapter;1701HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));1702struct dm_struct *dm = &hal_data->DM_OutSrc;17031704PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);1705beamforming_timer_callback(dm);1706#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)1707struct dm_struct *dm = (struct dm_struct *)function_context;1708void *adapter = dm->adapter;17091710if (*dm->is_net_closed == true)1711return;1712phydm_run_in_thread_cmd(dm, beamforming_timer_callback, adapter);1713#endif1714}17151716void phydm_beamforming_init(1717void *dm_void)1718{1719struct dm_struct *dm = (struct dm_struct *)dm_void;1720struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1721struct _RT_BEAMFORMING_OID_INFO *beam_oid_info = &beam_info->beamforming_oid_info;1722#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1723void *adapter = dm->adapter;1724HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));17251726#ifdef BEAMFORMING_VERSION_11727if (hal_data->beamforming_version != BEAMFORMING_VERSION_1) {1728return;1729}1730#endif1731#endif17321733beam_oid_info->sound_oid_mode = SOUNDING_STOP_OID_TIMER;1734PHYDM_DBG(dm, DBG_TXBF, "%s mode (%d)\n", __func__,1735beam_oid_info->sound_oid_mode);17361737beam_info->beamformee_su_cnt = 0;1738beam_info->beamformer_su_cnt = 0;1739beam_info->beamformee_mu_cnt = 0;1740beam_info->beamformer_mu_cnt = 0;1741beam_info->beamformee_mu_reg_maping = 0;1742beam_info->mu_ap_index = 0;1743beam_info->is_mu_sounding = false;1744beam_info->first_mu_bfee_index = 0xFF;1745beam_info->apply_v_matrix = true;1746beam_info->snding3ss = false;17471748#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1749beam_info->source_adapter = dm->adapter;1750#endif1751hal_com_txbf_beamform_init(dm);1752}17531754boolean1755phydm_acting_determine(1756void *dm_void,1757enum phydm_acting_type type)1758{1759struct dm_struct *dm = (struct dm_struct *)dm_void;1760boolean ret = false;1761#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1762void *adapter = dm->beamforming_info.source_adapter;1763#else1764struct _ADAPTER *adapter = dm->adapter;1765#endif17661767#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)1768if (type == phydm_acting_as_ap)1769ret = ACTING_AS_AP(adapter);1770else if (type == phydm_acting_as_ibss)1771ret = ACTING_AS_IBSS(((PADAPTER)(adapter)));1772#elif (DM_ODM_SUPPORT_TYPE & ODM_CE)1773struct mlme_priv *pmlmepriv = &adapter->mlmepriv;17741775if (type == phydm_acting_as_ap)1776ret = check_fwstate(pmlmepriv, WIFI_AP_STATE);1777else if (type == phydm_acting_as_ibss)1778ret = check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);1779#endif17801781return ret;1782}17831784void beamforming_enter(void *dm_void, u16 sta_idx, u8 *my_mac_addr)1785{1786struct dm_struct *dm = (struct dm_struct *)dm_void;1787u8 bfer_bfee_idx = 0xff;17881789if (beamforming_init_entry(dm, sta_idx, &bfer_bfee_idx, my_mac_addr))1790hal_com_txbf_set(dm, TXBF_SET_SOUNDING_ENTER, (u8 *)&bfer_bfee_idx);17911792PHYDM_DBG(dm, DBG_TXBF, "[%s] End!\n", __func__);1793}17941795void beamforming_leave(1796void *dm_void,1797u8 *RA)1798{1799struct dm_struct *dm = (struct dm_struct *)dm_void;18001801if (RA != NULL) {1802beamforming_deinit_entry(dm, RA);1803phydm_beamforming_notify(dm);1804}18051806PHYDM_DBG(dm, DBG_TXBF, "[%s] End!!\n", __func__);1807}18081809#if 01810/* Nobody calls this function */1811void1812phydm_beamforming_set_txbf_en(1813void *dm_void,1814u8 mac_id,1815boolean is_txbf1816)1817{1818struct dm_struct *dm = (struct dm_struct *)dm_void;1819u8 idx = 0;1820struct _RT_BEAMFORMEE_ENTRY *entry;18211822PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);18231824entry = phydm_beamforming_get_entry_by_mac_id(dm, mac_id, &idx);18251826if (entry == NULL)1827return;1828else1829entry->is_txbf = is_txbf;18301831PHYDM_DBG(dm, DBG_TXBF, "%s mac_id %d TxBF %d\n", __func__,1832entry->mac_id, entry->is_txbf);18331834phydm_beamforming_notify(dm);1835}1836#endif18371838enum beamforming_cap1839phydm_beamforming_get_beam_cap(1840void *dm_void,1841struct _RT_BEAMFORMING_INFO *beam_info)1842{1843u8 i;1844boolean is_self_beamformer = false;1845boolean is_self_beamformee = false;1846struct _RT_BEAMFORMEE_ENTRY beamformee_entry;1847struct _RT_BEAMFORMER_ENTRY beamformer_entry;1848enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE;1849struct dm_struct *dm = (struct dm_struct *)dm_void;18501851PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);18521853for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {1854beamformee_entry = beam_info->beamformee_entry[i];18551856if (beamformee_entry.is_used) {1857is_self_beamformer = true;1858PHYDM_DBG(dm, DBG_TXBF,1859"[%s] BFee entry %d is_used=true\n", __func__,1860i);1861break;1862}1863}18641865for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {1866beamformer_entry = beam_info->beamformer_entry[i];18671868if (beamformer_entry.is_used) {1869is_self_beamformee = true;1870PHYDM_DBG(dm, DBG_TXBF,1871"[%s]: BFer entry %d is_used=true\n",1872__func__, i);1873break;1874}1875}18761877if (is_self_beamformer)1878beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP);1879if (is_self_beamformee)1880beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP);18811882return beamform_cap;1883}18841885boolean1886beamforming_control_v1(1887void *dm_void,1888u8 *RA,1889u8 AID,1890u8 mode,1891enum channel_width BW,1892u8 rate)1893{1894struct dm_struct *dm = (struct dm_struct *)dm_void;1895boolean ret = true;18961897PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);18981899PHYDM_DBG(dm, DBG_TXBF, "AID (%d), mode (%d), BW (%d)\n", AID, mode,1900BW);19011902switch (mode) {1903case 0:1904ret = beamforming_start_v1(dm, RA, 0, BW, rate);1905break;1906case 1:1907ret = beamforming_start_v1(dm, RA, 1, BW, rate);1908break;1909case 2:1910phydm_beamforming_ndpa_rate(dm, BW, rate);1911ret = beamforming_send_vht_ndpa_packet(dm, RA, AID, BW, NORMAL_QUEUE);1912break;1913case 3:1914phydm_beamforming_ndpa_rate(dm, BW, rate);1915ret = beamforming_send_ht_ndpa_packet(dm, RA, BW, NORMAL_QUEUE);1916break;1917}1918return ret;1919}19201921/*Only OID uses this function*/1922boolean1923phydm_beamforming_control_v2(1924void *dm_void,1925u8 idx,1926u8 mode,1927enum channel_width BW,1928u16 period)1929{1930struct dm_struct *dm = (struct dm_struct *)dm_void;1931struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1932struct _RT_BEAMFORMING_OID_INFO *beam_oid_info = &beam_info->beamforming_oid_info;19331934PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);1935PHYDM_DBG(dm, DBG_TXBF, "idx (%d), mode (%d), BW (%d), period (%d)\n",1936idx, mode, BW, period);19371938beam_oid_info->sound_oid_idx = idx;1939beam_oid_info->sound_oid_mode = (enum sounding_mode)mode;1940beam_oid_info->sound_oid_bw = BW;1941beam_oid_info->sound_oid_period = period;19421943phydm_beamforming_notify(dm);19441945return true;1946}19471948void phydm_beamforming_watchdog(1949void *dm_void)1950{1951struct dm_struct *dm = (struct dm_struct *)dm_void;1952struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;19531954PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);19551956if (beam_info->beamformee_su_cnt == 0)1957return;19581959beamforming_dym_period(dm, 0);1960}1961enum beamforming_cap1962phydm_get_beamform_cap(1963void *dm_void)1964{1965struct dm_struct *dm = (struct dm_struct *)dm_void;1966struct cmn_sta_info *sta = NULL;1967struct bf_cmn_info *bf_info = NULL;1968struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;1969void *adapter = dm->adapter;1970enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE;1971u8 macid;1972u8 ht_curbeamformcap = 0;1973u16 vht_curbeamformcap = 0;19741975#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)1976PMGNT_INFO p_MgntInfo = &(((PADAPTER)(adapter))->MgntInfo);1977PRT_VERY_HIGH_THROUGHPUT p_vht_info = GET_VHT_INFO(p_MgntInfo);1978PRT_HIGH_THROUGHPUT p_ht_info = GET_HT_INFO(p_MgntInfo);19791980ht_curbeamformcap = p_ht_info->HtCurBeamform;1981vht_curbeamformcap = p_vht_info->VhtCurBeamform;19821983PHYDM_DBG(dm, DBG_ANT_DIV,1984"[%s] WIN ht_curcap = %d ; vht_curcap = %d\n", __func__,1985ht_curbeamformcap, vht_curbeamformcap);19861987if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) /*We are Beamformee because the STA is Beamformer*/1988beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_HT_EXPLICIT | BEAMFORMEE_CAP));19891990/*We are Beamformer because the STA is Beamformee*/1991if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMEE_ENABLE))1992beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP));19931994#if (ODM_IC_11AC_SERIES_SUPPORT == 1)19951996/* We are Beamformee because the STA is SU Beamformer*/1997if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMER_ENABLE))1998beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP));19992000/* We are Beamformer because the STA is SU Beamformee*/2001if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))2002beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP));20032004/* We are Beamformee because the STA is MU Beamformer*/2005if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE))2006beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP));2007#endif2008#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)20092010for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) {2011sta = dm->phydm_sta_info[macid];20122013if (!is_sta_active(sta))2014continue;20152016bf_info = &sta->bf_info;2017vht_curbeamformcap = bf_info->vht_beamform_cap;2018ht_curbeamformcap = bf_info->ht_beamform_cap;20192020if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) /*We are Beamformee because the STA is Beamformer*/2021beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_HT_EXPLICIT | BEAMFORMEE_CAP));20222023/*We are Beamformer because the STA is Beamformee*/2024if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMEE_ENABLE))2025beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP));20262027#if (ODM_IC_11AC_SERIES_SUPPORT == 1)2028/* We are Beamformee because the STA is SU Beamformer*/2029if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMER_ENABLE))2030beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP));20312032/* We are Beamformer because the STA is SU Beamformee*/2033if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))2034beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP));20352036/* We are Beamformee because the STA is MU Beamformer*/2037if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE))2038beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP));2039#endif2040}2041PHYDM_DBG(dm, DBG_ANT_DIV, "[%s] CE ht_curcap = %d ; vht_curcap = %d\n",2042__func__, ht_curbeamformcap, vht_curbeamformcap);20432044#endif20452046return beamform_cap;2047}20482049#endif205020512052