Path: blob/master/ALFA-W1F1/RTL8814AU/core/rtw_vht.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_VHT_C1516#include <drv_types.h>17#include <hal_data.h>1819#ifdef CONFIG_80211AC_VHT20const u16 _vht_max_mpdu_len[] = {213895,227991,2311454,240,25};2627const u8 _vht_sup_ch_width_set_to_bw_cap[] = {28BW_CAP_80M,29BW_CAP_80M | BW_CAP_160M,30BW_CAP_80M | BW_CAP_160M | BW_CAP_80_80M,310,32};3334const char *const _vht_sup_ch_width_set_str[] = {35"80MHz",36"160MHz",37"160MHz & 80+80MHz",38"BW-RSVD",39};4041void dump_vht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len)42{43if (buf_len != VHT_CAP_IE_LEN) {44RTW_PRINT_SEL(sel, "Invalid VHT capability IE len:%d != %d\n", buf_len, VHT_CAP_IE_LEN);45return;46}4748RTW_PRINT_SEL(sel, "cap_info:%02x %02x %02x %02x: MAX_MPDU_LEN:%u %s%s%s%s%s RX-STBC:%u MAX_AMPDU_LEN:%u\n"49, *(buf), *(buf + 1), *(buf + 2), *(buf + 3)50, vht_max_mpdu_len(GET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(buf))51, vht_sup_ch_width_set_str(GET_VHT_CAPABILITY_ELE_CHL_WIDTH(buf))52, GET_VHT_CAPABILITY_ELE_RX_LDPC(buf) ? " RX-LDPC" : ""53, GET_VHT_CAPABILITY_ELE_SHORT_GI80M(buf) ? " SGI-80" : ""54, GET_VHT_CAPABILITY_ELE_SHORT_GI160M(buf) ? " SGI-160" : ""55, GET_VHT_CAPABILITY_ELE_TX_STBC(buf) ? " TX-STBC" : ""56, GET_VHT_CAPABILITY_ELE_RX_STBC(buf)57, VHT_MAX_AMPDU_LEN(GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(buf))58);59}6061void dump_vht_cap_ie(void *sel, const u8 *ie, u32 ie_len)62{63const u8 *vht_cap_ie;64sint vht_cap_ielen;6566vht_cap_ie = rtw_get_ie(ie, WLAN_EID_VHT_CAPABILITY, &vht_cap_ielen, ie_len);67if (!ie || vht_cap_ie != ie)68return;6970dump_vht_cap_ie_content(sel, vht_cap_ie + 2, vht_cap_ielen);71}7273const char *const _vht_op_ch_width_str[] = {74"20 or 40MHz",75"80MHz",76"160MHz",77"80+80MHz",78"BW-RSVD",79};8081void dump_vht_op_ie_content(void *sel, const u8 *buf, u32 buf_len)82{83if (buf_len != VHT_OP_IE_LEN) {84RTW_PRINT_SEL(sel, "Invalid VHT operation IE len:%d != %d\n", buf_len, VHT_OP_IE_LEN);85return;86}8788RTW_PRINT_SEL(sel, "%s, ch0:%u, ch1:%u\n"89, vht_op_ch_width_str(GET_VHT_OPERATION_ELE_CHL_WIDTH(buf))90, GET_VHT_OPERATION_ELE_CENTER_FREQ1(buf)91, GET_VHT_OPERATION_ELE_CENTER_FREQ2(buf)92);93}9495void dump_vht_op_ie(void *sel, const u8 *ie, u32 ie_len)96{97const u8 *vht_op_ie;98sint vht_op_ielen;99100vht_op_ie = rtw_get_ie(ie, WLAN_EID_VHT_OPERATION, &vht_op_ielen, ie_len);101if (!ie || vht_op_ie != ie)102return;103104dump_vht_op_ie_content(sel, vht_op_ie + 2, vht_op_ielen);105}106107/* 20/40/80, ShortGI, MCS Rate */108const u16 VHT_MCS_DATA_RATE[3][2][30] = {109{ {11013, 26, 39, 52, 78, 104, 117, 130, 156, 156,11126, 52, 78, 104, 156, 208, 234, 260, 312, 312,11239, 78, 117, 156, 234, 312, 351, 390, 468, 520113}, /* Long GI, 20MHz */114{11514, 29, 43, 58, 87, 116, 130, 144, 173, 173,11629, 58, 87, 116, 173, 231, 260, 289, 347, 347,11743, 87, 130, 173, 260, 347, 390, 433, 520, 578118}119}, /* Short GI, 20MHz */120{ {12127, 54, 81, 108, 162, 216, 243, 270, 324, 360,12254, 108, 162, 216, 324, 432, 486, 540, 648, 720,12381, 162, 243, 324, 486, 648, 729, 810, 972, 1080124}, /* Long GI, 40MHz */125{12630, 60, 90, 120, 180, 240, 270, 300, 360, 400,12760, 120, 180, 240, 360, 480, 540, 600, 720, 800,12890, 180, 270, 360, 540, 720, 810, 900, 1080, 1200129}130}, /* Short GI, 40MHz */131{ {13259, 117, 176, 234, 351, 468, 527, 585, 702, 780,133117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560,134176, 351, 527, 702, 1053, 1404, 1580, 1755, 2106, 2340135}, /* Long GI, 80MHz */136{13765, 130, 195, 260, 390, 520, 585, 650, 780, 867,138130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734,139195, 390, 585, 780, 1170, 1560, 1755, 1950, 2340, 2600140}141} /* Short GI, 80MHz */142};143144u8 rtw_get_vht_highest_rate(u8 *pvht_mcs_map)145{146u8 i, j;147u8 bit_map;148u8 vht_mcs_rate = 0;149150for (i = 0; i < 2; i++) {151if (pvht_mcs_map[i] != 0xff) {152for (j = 0; j < 8; j += 2) {153bit_map = (pvht_mcs_map[i] >> j) & 3;154155if (bit_map != 3)156vht_mcs_rate = MGN_VHT1SS_MCS7 + 10 * j / 2 + i * 40 + bit_map; /* VHT rate indications begin from 0x90 */157}158}159}160161/* RTW_INFO("HighestVHTMCSRate is %x\n", vht_mcs_rate); */162return vht_mcs_rate;163}164165u8 rtw_vht_mcsmap_to_nss(u8 *pvht_mcs_map)166{167u8 i, j;168u8 bit_map;169u8 nss = 0;170171for (i = 0; i < 2; i++) {172if (pvht_mcs_map[i] != 0xff) {173for (j = 0; j < 8; j += 2) {174bit_map = (pvht_mcs_map[i] >> j) & 3;175176if (bit_map != 3)177nss++;178}179}180}181182/* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */183return nss;184}185186void rtw_vht_nss_to_mcsmap(u8 nss, u8 *target_mcs_map, u8 *cur_mcs_map)187{188u8 i, j;189u8 cur_rate, target_rate;190191for (i = 0; i < 2; i++) {192target_mcs_map[i] = 0;193for (j = 0; j < 8; j += 2) {194cur_rate = (cur_mcs_map[i] >> j) & 3;195if (cur_rate == 3) /* 0x3 indicates not supported that num of SS */196target_rate = 3;197else if (nss <= ((j / 2) + i * 4))198target_rate = 3;199else200target_rate = cur_rate;201202target_mcs_map[i] |= (target_rate << j);203}204}205206/* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */207}208209u16 rtw_vht_mcs_to_data_rate(u8 bw, u8 short_GI, u8 vht_mcs_rate)210{211if (vht_mcs_rate > MGN_VHT3SS_MCS9)212vht_mcs_rate = MGN_VHT3SS_MCS9;213/* RTW_INFO("bw=%d, short_GI=%d, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)=%d\n", bw, short_GI, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)); */214return VHT_MCS_DATA_RATE[bw][short_GI][((vht_mcs_rate - MGN_VHT1SS_MCS0) & 0x3f)];215}216217void rtw_vht_use_default_setting(_adapter *padapter)218{219struct mlme_priv *pmlmepriv = &padapter->mlmepriv;220struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;221struct registry_priv *pregistrypriv = &padapter->registrypriv;222BOOLEAN bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE;223#ifdef CONFIG_BEAMFORMING224BOOLEAN bHwSupportBeamformer = _FALSE, bHwSupportBeamformee = _FALSE;225u8 mu_bfer, mu_bfee;226#endif /* CONFIG_BEAMFORMING */227u8 tx_nss, rx_nss;228struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);229struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);230pvhtpriv->sgi_80m = TEST_FLAG(pregistrypriv->short_gi, BIT2) ? _TRUE : _FALSE;231232/* LDPC support */233rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport);234CLEAR_FLAGS(pvhtpriv->ldpc_cap);235if (bHwLDPCSupport) {236if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT0))237SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX);238}239rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport);240if (bHwLDPCSupport) {241if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT1))242SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX);243}244if (pvhtpriv->ldpc_cap)245RTW_INFO("[VHT] Support LDPC = 0x%02X\n", pvhtpriv->ldpc_cap);246247/* STBC */248rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport);249CLEAR_FLAGS(pvhtpriv->stbc_cap);250if (bHwSTBCSupport) {251if (TEST_FLAG(pregistrypriv->stbc_cap, BIT1))252SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX);253}254rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport);255if (bHwSTBCSupport) {256if (TEST_FLAG(pregistrypriv->stbc_cap, BIT0))257SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX);258}259if (pvhtpriv->stbc_cap)260RTW_INFO("[VHT] Support STBC = 0x%02X\n", pvhtpriv->stbc_cap);261262/* Beamforming setting */263CLEAR_FLAGS(pvhtpriv->beamform_cap);264#ifdef CONFIG_BEAMFORMING265#ifdef RTW_BEAMFORMING_VERSION_2266/* only enable beamforming in STA client mode */267if (MLME_IS_STA(padapter) && !MLME_IS_GC(padapter)268&& !MLME_IS_ADHOC(padapter)269&& !MLME_IS_MESH(padapter))270#endif271{272rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER,273(u8 *)&bHwSupportBeamformer);274rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE,275(u8 *)&bHwSupportBeamformee);276mu_bfer = _FALSE;277mu_bfee = _FALSE;278rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMER, &mu_bfer);279rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMEE, &mu_bfee);280if (TEST_FLAG(pregistrypriv->beamform_cap, BIT0) && bHwSupportBeamformer) {281#ifdef CONFIG_CONCURRENT_MODE282if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {283SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);284RTW_INFO("[VHT] CONCURRENT AP Support Beamformer\n");285if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2))286&& (_TRUE == mu_bfer)) {287SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);288RTW_INFO("[VHT] Support MU-MIMO AP\n");289}290} else291RTW_INFO("[VHT] CONCURRENT not AP ;not allow Support Beamformer\n");292#else293SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);294RTW_INFO("[VHT] Support Beamformer\n");295if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2))296&& (_TRUE == mu_bfer)297&& ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {298SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);299RTW_INFO("[VHT] Support MU-MIMO AP\n");300}301#endif302}303if (TEST_FLAG(pregistrypriv->beamform_cap, BIT1) && bHwSupportBeamformee) {304SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);305RTW_INFO("[VHT] Support Beamformee\n");306if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(3))307&& (_TRUE == mu_bfee)308&& ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)) {309SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE);310RTW_INFO("[VHT] Support MU-MIMO STA\n");311}312}313}314#endif /* CONFIG_BEAMFORMING */315316pvhtpriv->ampdu_len = pregistrypriv->ampdu_factor;317318tx_nss = GET_HAL_TX_NSS(padapter);319rx_nss = GET_HAL_RX_NSS(padapter);320321/* for now, vhtpriv.vht_mcs_map comes from RX NSS */322rtw_vht_nss_to_mcsmap(rx_nss, pvhtpriv->vht_mcs_map, pregistrypriv->vht_rx_mcs_map);323pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map);324}325326u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss)327{328u8 i, j, tmp;329u64 bitmap = 0;330u8 bits_nss = nss * 2;331332for (i = j = 0; i < bits_nss; i += 2, j += 10) {333/* every two bits means single sptial stream */334tmp = (mcs_map[i / 8] >> i) & 3;335336switch (tmp) {337case 2:338bitmap = bitmap | (0x03ff << j);339break;340case 1:341bitmap = bitmap | (0x01ff << j);342break;343case 0:344bitmap = bitmap | (0x00ff << j);345break;346default:347break;348}349}350351RTW_INFO("vht_mcs_map=%02x %02x, nss=%u => bitmap=%016llx\n"352, mcs_map[0], mcs_map[1], nss, bitmap);353354return bitmap;355}356357#ifdef CONFIG_BEAMFORMING358void update_sta_vht_info_apmode_bf_cap(_adapter *padapter, struct sta_info *psta)359{360struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);361struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv;362struct vht_priv *pvhtpriv_sta = &psta->vhtpriv;363u16 cur_beamform_cap = 0;364365/* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */366if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) &&367GET_VHT_CAPABILITY_ELE_SU_BFEE(pvhtpriv_sta->vht_cap)) {368SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);369/*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/370SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pvhtpriv_sta->vht_cap) << 8);371}372373/* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */374if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) &&375GET_VHT_CAPABILITY_ELE_SU_BFER(pvhtpriv_sta->vht_cap)) {376SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);377/*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/378SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pvhtpriv_sta->vht_cap) << 12);379}380381if (cur_beamform_cap)382RTW_INFO("Current STA(%d) VHT Beamforming Setting = %02X\n", psta->cmn.aid, cur_beamform_cap);383384pvhtpriv_sta->beamform_cap = cur_beamform_cap;385psta->cmn.bf_info.vht_beamform_cap = cur_beamform_cap;386}387#endif388389void update_sta_vht_info_apmode(_adapter *padapter, void *sta)390{391struct sta_info *psta = (struct sta_info *)sta;392struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);393struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;394struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv;395struct vht_priv *pvhtpriv_sta = &psta->vhtpriv;396u8 cur_ldpc_cap = 0, cur_stbc_cap = 0;397s8 bw_mode = -1;398u8 *pcap_mcs;399400if (pvhtpriv_sta->vht_option == _FALSE)401return;402403if (pvhtpriv_sta->op_present) {404switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(pvhtpriv_sta->vht_op)) {405case 1: /* 80MHz */406case 2: /* 160MHz */407case 3: /* 80+80 */408bw_mode = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */409break;410}411}412413if (pvhtpriv_sta->notify_present)414bw_mode = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&pvhtpriv_sta->vht_op_mode_notify);415else if (MLME_IS_AP(padapter)) {416/* for VHT client without Operating Mode Notify IE; minimal 80MHz */417if (bw_mode < CHANNEL_WIDTH_80)418bw_mode = CHANNEL_WIDTH_80;419}420421if (bw_mode != -1)422psta->cmn.bw_mode = bw_mode; /* update bw_mode only if get value from VHT IEs */423424psta->cmn.ra_info.is_vht_enable = _TRUE;425426/* B4 Rx LDPC */427if (TEST_FLAG(pvhtpriv_ap->ldpc_cap, LDPC_VHT_ENABLE_TX) &&428GET_VHT_CAPABILITY_ELE_RX_LDPC(pvhtpriv_sta->vht_cap)) {429SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX));430RTW_INFO("Current STA(%d) VHT LDPC = %02X\n", psta->cmn.aid, cur_ldpc_cap);431}432pvhtpriv_sta->ldpc_cap = cur_ldpc_cap;433434if (psta->cmn.bw_mode > pmlmeext->cur_bwmode)435psta->cmn.bw_mode = pmlmeext->cur_bwmode;436437if (psta->cmn.bw_mode == CHANNEL_WIDTH_80) {438/* B5 Short GI for 80 MHz */439pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE;440/* RTW_INFO("Current STA ShortGI80MHz = %d\n", pvhtpriv_sta->sgi_80m); */441} else if (psta->cmn.bw_mode >= CHANNEL_WIDTH_160) {442/* B5 Short GI for 80 MHz */443pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE;444/* RTW_INFO("Current STA ShortGI160MHz = %d\n", pvhtpriv_sta->sgi_80m); */445}446447/* B8 B9 B10 Rx STBC */448if (TEST_FLAG(pvhtpriv_ap->stbc_cap, STBC_VHT_ENABLE_TX) &&449GET_VHT_CAPABILITY_ELE_RX_STBC(pvhtpriv_sta->vht_cap)) {450SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX));451RTW_INFO("Current STA(%d) VHT STBC = %02X\n", psta->cmn.aid, cur_stbc_cap);452}453pvhtpriv_sta->stbc_cap = cur_stbc_cap;454455#ifdef CONFIG_BEAMFORMING456update_sta_vht_info_apmode_bf_cap(padapter, psta);457#endif458459/* B23 B24 B25 Maximum A-MPDU Length Exponent */460pvhtpriv_sta->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pvhtpriv_sta->vht_cap);461462pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pvhtpriv_sta->vht_cap);463_rtw_memcpy(pvhtpriv_sta->vht_mcs_map, pcap_mcs, 2);464pvhtpriv_sta->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv_sta->vht_mcs_map);465}466467void update_hw_vht_param(_adapter *padapter)468{469struct mlme_priv *pmlmepriv = &padapter->mlmepriv;470struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;471struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;472struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);473u8 ht_AMPDU_len;474475ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;476477if (pvhtpriv->ampdu_len > ht_AMPDU_len)478rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len));479}480481#ifdef ROKU_PRIVATE482u8 VHT_get_ss_from_map(u8 *vht_mcs_map)483{484u8 i, j;485u8 ss = 0;486487for (i = 0; i < 2; i++) {488if (vht_mcs_map[i] != 0xff) {489for (j = 0; j < 8; j += 2) {490if (((vht_mcs_map[i] >> j) & 0x03) == 0x03)491break;492ss++;493}494}495496}497498return ss;499}500501void VHT_caps_handler_infra_ap(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE)502{503struct mlme_priv *pmlmepriv = &padapter->mlmepriv;504struct vht_priv_infra_ap *pvhtpriv = &pmlmepriv->vhtpriv_infra_ap;505u8 cur_stbc_cap_infra_ap = 0;506u16 cur_beamform_cap_infra_ap = 0;507u8 *pcap_mcs;508u8 *pcap_mcs_tx;509u8 Rx_ss = 0, Tx_ss = 0;510511struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;512struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);513514if (pIE == NULL)515return;516517pmlmeinfo->ht_vht_received |= BIT(1);518519pvhtpriv->ldpc_cap_infra_ap = GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data);520521if (GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data))522SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_RX);523if (GET_VHT_CAPABILITY_ELE_TX_STBC(pIE->data))524SET_FLAG(cur_stbc_cap_infra_ap, STBC_VHT_ENABLE_TX);525pvhtpriv->stbc_cap_infra_ap = cur_stbc_cap_infra_ap;526527/*store ap info for channel bandwidth*/528pvhtpriv->channel_width_infra_ap = GET_VHT_CAPABILITY_ELE_CHL_WIDTH(pIE->data);529530/*check B11: SU Beamformer Capable and B12: SU Beamformee B19: MU Beamformer B20:MU Beamformee*/531if (GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data))532SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);533if (GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data))534SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);535if (GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data))536SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);537if (GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data))538SET_FLAG(cur_beamform_cap_infra_ap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE);539pvhtpriv->beamform_cap_infra_ap = cur_beamform_cap_infra_ap;540541/*store information about vht_mcs_set*/542pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data);543pcap_mcs_tx = GET_VHT_CAPABILITY_ELE_TX_MCS(pIE->data);544_rtw_memcpy(pvhtpriv->vht_mcs_map_infra_ap, pcap_mcs, 2);545_rtw_memcpy(pvhtpriv->vht_mcs_map_tx_infra_ap, pcap_mcs_tx, 2);546547Rx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_infra_ap);548Tx_ss = VHT_get_ss_from_map(pvhtpriv->vht_mcs_map_tx_infra_ap);549if (Rx_ss >= Tx_ss) {550pvhtpriv->number_of_streams_infra_ap = Rx_ss;551} else{552pvhtpriv->number_of_streams_infra_ap = Tx_ss;553}554555}556#endif /* ROKU_PRIVATE */557558void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE)559{560struct mlme_priv *pmlmepriv = &padapter->mlmepriv;561struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;562struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;563struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);564u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, rx_nss = 0;565u16 cur_beamform_cap = 0;566u8 *pcap_mcs;567568if (pIE == NULL)569return;570571if (pvhtpriv->vht_option == _FALSE)572return;573574pmlmeinfo->VHT_enable = 1;575576/* B4 Rx LDPC */577if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX) &&578GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data)) {579SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX));580RTW_INFO("Current VHT LDPC Setting = %02X\n", cur_ldpc_cap);581}582pvhtpriv->ldpc_cap = cur_ldpc_cap;583584/* B5 Short GI for 80 MHz */585pvhtpriv->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pIE->data) & pvhtpriv->sgi_80m) ? _TRUE : _FALSE;586/* RTW_INFO("Current ShortGI80MHz = %d\n", pvhtpriv->sgi_80m); */587588/* B8 B9 B10 Rx STBC */589if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX) &&590GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data)) {591SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX));592RTW_INFO("Current VHT STBC Setting = %02X\n", cur_stbc_cap);593}594pvhtpriv->stbc_cap = cur_stbc_cap;595#ifdef CONFIG_BEAMFORMING596#ifdef RTW_BEAMFORMING_VERSION_2597/*598* B11 SU Beamformer Capable,599* the target supports Beamformer and we are Beamformee600*/601if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)602&& GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) {603SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);604605/* Shift to BEAMFORMING_VHT_BEAMFORMEE_STS_CAP */606SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8);607608/*609* B19 MU Beamformer Capable,610* the target supports Beamformer and we are Beamformee611*/612if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)613&& GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data))614SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE);615}616617/*618* B12 SU Beamformee Capable,619* the target supports Beamformee and we are Beamformer620*/621if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)622&& GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) {623SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);624625/* Shit to BEAMFORMING_VHT_BEAMFORMER_SOUND_DIM */626SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12);627628/*629* B20 MU Beamformee Capable,630* the target supports Beamformee and we are Beamformer631*/632if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)633&& GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data))634SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE);635}636637pvhtpriv->beamform_cap = cur_beamform_cap;638RTW_INFO("Current VHT Beamforming Setting=0x%04X\n", cur_beamform_cap);639#else /* !RTW_BEAMFORMING_VERSION_2 */640/* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */641if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) &&642GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) {643SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE);644/*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/645SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8);646}647648/* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */649if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) &&650GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) {651SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE);652/*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/653SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12);654655}656pvhtpriv->beamform_cap = cur_beamform_cap;657if (cur_beamform_cap)658RTW_INFO("Current VHT Beamforming Setting = %02X\n", cur_beamform_cap);659#endif /* !RTW_BEAMFORMING_VERSION_2 */660#endif /* CONFIG_BEAMFORMING */661/* B23 B24 B25 Maximum A-MPDU Length Exponent */662pvhtpriv->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pIE->data);663664pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data);665rx_nss = GET_HAL_RX_NSS(padapter);666rtw_vht_nss_to_mcsmap(rx_nss, pvhtpriv->vht_mcs_map, pcap_mcs);667pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map);668}669670void VHT_operation_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE)671{672struct mlme_priv *pmlmepriv = &padapter->mlmepriv;673struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;674675if (pIE == NULL)676return;677678if (pvhtpriv->vht_option == _FALSE)679return;680}681682void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, void *sta)683{684struct sta_info *psta = (struct sta_info *)sta;685struct mlme_priv *pmlmepriv = &padapter->mlmepriv;686struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;687struct registry_priv *regsty = adapter_to_regsty(padapter);688u8 target_bw;689u8 target_rxss, current_rxss;690u8 update_ra = _FALSE;691u8 tx_nss = 0;692693if (pvhtpriv->vht_option == _FALSE)694return;695696target_bw = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(pframe);697tx_nss = GET_HAL_TX_NSS(padapter);698target_rxss = rtw_min(tx_nss, (GET_VHT_OPERATING_MODE_FIELD_RX_NSS(pframe) + 1));699700if (target_bw != psta->cmn.bw_mode) {701if (hal_is_bw_support(padapter, target_bw)702&& REGSTY_IS_BW_5G_SUPPORT(regsty, target_bw)703) {704update_ra = _TRUE;705psta->cmn.bw_mode = target_bw;706}707}708709current_rxss = rtw_vht_mcsmap_to_nss(psta->vhtpriv.vht_mcs_map);710if (target_rxss != current_rxss) {711u8 vht_mcs_map[2] = {};712713update_ra = _TRUE;714715rtw_vht_nss_to_mcsmap(target_rxss, vht_mcs_map, psta->vhtpriv.vht_mcs_map);716_rtw_memcpy(psta->vhtpriv.vht_mcs_map, vht_mcs_map, 2);717718rtw_hal_update_sta_ra_info(padapter, psta);719}720721if (update_ra)722rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta);723}724725u32 rtw_build_vht_operation_ie(_adapter *padapter, u8 *pbuf, u8 channel)726{727struct registry_priv *pregistrypriv = &padapter->registrypriv;728struct mlme_priv *pmlmepriv = &padapter->mlmepriv;729struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;730/* struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; */731u8 ChnlWidth, center_freq, bw_mode;732u32 len = 0;733u8 operation[5];734735_rtw_memset(operation, 0, 5);736737bw_mode = REGSTY_BW_5G(pregistrypriv); /* TODO: control op bw with other info */738739if (hal_chk_bw_cap(padapter, BW_CAP_80M | BW_CAP_160M)740&& REGSTY_BW_5G(pregistrypriv) >= CHANNEL_WIDTH_80741) {742center_freq = rtw_get_center_ch(channel, bw_mode, HAL_PRIME_CHNL_OFFSET_LOWER);743ChnlWidth = 1;744} else {745center_freq = 0;746ChnlWidth = 0;747}748749750SET_VHT_OPERATION_ELE_CHL_WIDTH(operation, ChnlWidth);751/* center frequency */752SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(operation, center_freq);/* Todo: need to set correct center channel */753SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(operation, 0);754755_rtw_memcpy(operation + 3, pvhtpriv->vht_mcs_map, 2);756757rtw_set_ie(pbuf, EID_VHTOperation, 5, operation, &len);758759return len;760}761762u32 rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw)763{764/* struct registry_priv *pregistrypriv = &padapter->registrypriv; */765struct mlme_priv *pmlmepriv = &padapter->mlmepriv;766struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;767u32 len = 0;768u8 opmode = 0;769u8 chnl_width, rx_nss;770771chnl_width = bw;772rx_nss = rtw_vht_mcsmap_to_nss(pvhtpriv->vht_mcs_map);773774SET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&opmode, chnl_width);775SET_VHT_OPERATING_MODE_FIELD_RX_NSS(&opmode, (rx_nss - 1));776SET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(&opmode, 0); /* Todo */777778pvhtpriv->vht_op_mode_notify = opmode;779780pbuf = rtw_set_ie(pbuf, EID_OpModeNotification, 1, &opmode, &len);781782return len;783}784785u32 rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf)786{787u8 bw, rf_num, rx_stbc_nss = 0;788u16 HighestRate;789u8 *pcap, *pcap_mcs;790u32 len = 0;791u32 rx_packet_offset, max_recvbuf_sz;792struct registry_priv *pregistrypriv = &padapter->registrypriv;793struct mlme_priv *pmlmepriv = &padapter->mlmepriv;794struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;795struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;796struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);797798pcap = pvhtpriv->vht_cap;799_rtw_memset(pcap, 0, 32);800801/* B0 B1 Maximum MPDU Length */802rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset);803rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz);804805RTW_DBG("%s, line%d, Available RX buf size = %d bytes\n", __FUNCTION__, __LINE__, max_recvbuf_sz - rx_packet_offset);806807if ((max_recvbuf_sz - rx_packet_offset) >= 11454) {808SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 2);809RTW_INFO("%s, line%d, Set MAX MPDU len = 11454 bytes\n", __FUNCTION__, __LINE__);810} else if ((max_recvbuf_sz - rx_packet_offset) >= 7991) {811SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 1);812RTW_INFO("%s, line%d, Set MAX MPDU len = 7991 bytes\n", __FUNCTION__, __LINE__);813} else if ((max_recvbuf_sz - rx_packet_offset) >= 3895) {814SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 0);815RTW_INFO("%s, line%d, Set MAX MPDU len = 3895 bytes\n", __FUNCTION__, __LINE__);816} else817RTW_ERR("%s, line%d, Error!! Available RX buf size < 3895 bytes\n", __FUNCTION__, __LINE__);818819/* B2 B3 Supported Channel Width Set */820if (hal_chk_bw_cap(padapter, BW_CAP_160M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_160)) {821if (hal_chk_bw_cap(padapter, BW_CAP_80_80M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_80_80))822SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 2);823else824SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 1);825} else826SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 0);827828/* B4 Rx LDPC */829if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX)) {830SET_VHT_CAPABILITY_ELE_RX_LDPC(pcap, 1);831RTW_INFO("[VHT] Declare supporting RX LDPC\n");832}833834/* B5 ShortGI for 80MHz */835SET_VHT_CAPABILITY_ELE_SHORT_GI80M(pcap, pvhtpriv->sgi_80m ? 1 : 0); /* We can receive Short GI of 80M */836if (pvhtpriv->sgi_80m)837RTW_INFO("[VHT] Declare supporting SGI 80MHz\n");838839/* B6 ShortGI for 160MHz */840/* SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pcap, pvhtpriv->sgi_80m? 1 : 0); */841842/* B7 Tx STBC */843if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX)) {844SET_VHT_CAPABILITY_ELE_TX_STBC(pcap, 1);845RTW_INFO("[VHT] Declare supporting TX STBC\n");846}847848/* B8 B9 B10 Rx STBC */849if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX)) {850rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss));851852SET_VHT_CAPABILITY_ELE_RX_STBC(pcap, rx_stbc_nss);853RTW_INFO("[VHT] Declare supporting RX STBC = %d\n", rx_stbc_nss);854}855#ifdef CONFIG_BEAMFORMING856/* B11 SU Beamformer Capable */857if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {858SET_VHT_CAPABILITY_ELE_SU_BFER(pcap, 1);859RTW_INFO("[VHT] Declare supporting SU Bfer\n");860/* B16 17 18 Number of Sounding Dimensions */861rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num);862SET_VHT_CAPABILITY_ELE_SOUNDING_DIMENSIONS(pcap, rf_num);863/* B19 MU Beamformer Capable */864if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {865SET_VHT_CAPABILITY_ELE_MU_BFER(pcap, 1);866RTW_INFO("[VHT] Declare supporting MU Bfer\n");867}868}869870/* B12 SU Beamformee Capable */871if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) {872SET_VHT_CAPABILITY_ELE_SU_BFEE(pcap, 1);873RTW_INFO("[VHT] Declare supporting SU Bfee\n");874875rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num);876877/* IOT action suggested by Yu Chen 2017/3/3 */878#ifdef CONFIG_80211AC_VHT879if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) &&880!pvhtpriv->ap_is_mu_bfer)881rf_num = (rf_num >= 2 ? 2 : rf_num);882#endif883/* B13 14 15 Compressed Steering Number of Beamformer Antennas Supported */884SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(pcap, rf_num);885/* B20 SU Beamformee Capable */886if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) {887SET_VHT_CAPABILITY_ELE_MU_BFEE(pcap, 1);888RTW_INFO("[VHT] Declare supporting MU Bfee\n");889}890}891#endif/*CONFIG_BEAMFORMING*/892893/* B21 VHT TXOP PS */894SET_VHT_CAPABILITY_ELE_TXOP_PS(pcap, 0);895/* B22 +HTC-VHT Capable */896SET_VHT_CAPABILITY_ELE_HTC_VHT(pcap, 1);897/* B23 24 25 Maximum A-MPDU Length Exponent */898if (pregistrypriv->ampdu_factor != 0xFE)899SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, pregistrypriv->ampdu_factor);900else901SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, 7);902/* B26 27 VHT Link Adaptation Capable */903SET_VHT_CAPABILITY_ELE_LINK_ADAPTION(pcap, 0);904905pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pcap);906_rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2);907908pcap_mcs = GET_VHT_CAPABILITY_ELE_TX_MCS(pcap);909_rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2);910911/* find the largest bw supported by both registry and hal */912bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv));913914HighestRate = VHT_MCS_DATA_RATE[bw][pvhtpriv->sgi_80m][((pvhtpriv->vht_highest_rate - MGN_VHT1SS_MCS0) & 0x3f)];915HighestRate = (HighestRate + 1) >> 1;916917SET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest rx rate is 600Mbps. */918SET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest tx rate is 600Mbps. */919920pbuf = rtw_set_ie(pbuf, EID_VHTCapability, 12, pcap, &len);921922return len;923}924925u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len)926{927struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);928RT_CHANNEL_INFO *chset = rfctl->channel_set;929u32 ielen;930u8 max_bw;931u8 oper_ch, oper_bw = CHANNEL_WIDTH_20, oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;932u8 *out_vht_op_ie, *ht_op_ie, *vht_cap_ie, *vht_op_ie;933struct registry_priv *pregistrypriv = &padapter->registrypriv;934struct mlme_priv *pmlmepriv = &padapter->mlmepriv;935struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;936937rtw_vht_use_default_setting(padapter);938939ht_op_ie = rtw_get_ie(in_ie + 12, WLAN_EID_HT_OPERATION, &ielen, in_len - 12);940if (!ht_op_ie || ielen != HT_OP_IE_LEN)941goto exit;942vht_cap_ie = rtw_get_ie(in_ie + 12, EID_VHTCapability, &ielen, in_len - 12);943if (!vht_cap_ie || ielen != VHT_CAP_IE_LEN)944goto exit;945vht_op_ie = rtw_get_ie(in_ie + 12, EID_VHTOperation, &ielen, in_len - 12);946if (!vht_op_ie || ielen != VHT_OP_IE_LEN)947goto exit;948949/* VHT Capabilities element */950*pout_len += rtw_build_vht_cap_ie(padapter, out_ie + *pout_len);951952953/* VHT Operation element */954out_vht_op_ie = out_ie + *pout_len;955rtw_set_ie(out_vht_op_ie, EID_VHTOperation, VHT_OP_IE_LEN, vht_op_ie + 2 , pout_len);956957/* get primary channel from HT_OP_IE */958oper_ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2);959960/* find the largest bw supported by both registry and hal */961max_bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv));962963if (max_bw >= CHANNEL_WIDTH_40) {964/* get bw offset form HT_OP_IE */965if (GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2)) {966switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) {967case SCA:968oper_bw = CHANNEL_WIDTH_40;969oper_offset = HAL_PRIME_CHNL_OFFSET_LOWER;970break;971case SCB:972oper_bw = CHANNEL_WIDTH_40;973oper_offset = HAL_PRIME_CHNL_OFFSET_UPPER;974break;975}976}977978if (oper_bw == CHANNEL_WIDTH_40) {979switch (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2)) {980case 1: /* 80MHz */981case 2: /* 160MHz */982case 3: /* 80+80 */983oper_bw = CHANNEL_WIDTH_80; /* only support up to 80MHz for now */984break;985}986987oper_bw = rtw_min(oper_bw, max_bw);988989/* try downgrage bw to fit in channel plan setting */990while (!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset)991|| (IS_DFS_SLAVE_WITH_RD(rfctl)992&& !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))993&& rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset))994) {995oper_bw--;996if (oper_bw == CHANNEL_WIDTH_20) {997oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;998break;999}1000}1001}1002}10031004rtw_warn_on(!rtw_chset_is_chbw_valid(chset, oper_ch, oper_bw, oper_offset));1005if (IS_DFS_SLAVE_WITH_RD(rfctl) && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl)))1006rtw_warn_on(rtw_chset_is_chbw_non_ocp(chset, oper_ch, oper_bw, oper_offset));10071008/* update VHT_OP_IE */1009if (oper_bw < CHANNEL_WIDTH_80) {1010SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 0);1011SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, 0);1012SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0);1013} else if (oper_bw == CHANNEL_WIDTH_80) {1014u8 cch = rtw_get_center_ch(oper_ch, oper_bw, oper_offset);10151016SET_VHT_OPERATION_ELE_CHL_WIDTH(out_vht_op_ie + 2, 1);1017SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(out_vht_op_ie + 2, cch);1018SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(out_vht_op_ie + 2, 0);1019} else {1020RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(padapter), oper_bw);1021rtw_warn_on(1);1022}10231024/* Operating Mode Notification element */1025*pout_len += rtw_build_vht_op_mode_notify_ie(padapter, out_ie + *pout_len, oper_bw);10261027pvhtpriv->vht_option = _TRUE;10281029exit:1030return pvhtpriv->vht_option;10311032}10331034void VHTOnAssocRsp(_adapter *padapter)1035{1036struct mlme_priv *pmlmepriv = &padapter->mlmepriv;1037struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;1038struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;1039struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);1040u8 ht_AMPDU_len;10411042RTW_INFO("%s\n", __FUNCTION__);10431044if (!pmlmeinfo->HT_enable)1045return;10461047if (!pmlmeinfo->VHT_enable)1048return;10491050ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;10511052if (pvhtpriv->ampdu_len > ht_AMPDU_len)1053rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len));10541055rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MAX_TIME, (u8 *)(&pvhtpriv->vht_highest_rate));1056}10571058void rtw_vht_ies_attach(_adapter *padapter, WLAN_BSSID_EX *pnetwork)1059{1060struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);1061u8 cap_len, operation_len;1062uint len = 0;1063sint ie_len = 0;1064u8 *p = NULL;10651066p = rtw_get_ie(pnetwork->IEs + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len,1067(pnetwork->IELength - _BEACON_IE_OFFSET_));1068if (p && ie_len > 0)1069return;10701071rtw_vht_use_default_setting(padapter);10721073/* VHT Operation mode notifiy bit in Extended IE (127) */1074SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1);1075pmlmepriv->ext_capab_ie_len = 10;1076rtw_set_ie(pnetwork->IEs + pnetwork->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);1077pnetwork->IELength += pmlmepriv->ext_capab_ie_len;10781079/* VHT Capabilities element */1080cap_len = rtw_build_vht_cap_ie(padapter, pnetwork->IEs + pnetwork->IELength);1081pnetwork->IELength += cap_len;10821083/* VHT Operation element */1084operation_len = rtw_build_vht_operation_ie(padapter, pnetwork->IEs + pnetwork->IELength,1085pnetwork->Configuration.DSConfig);1086pnetwork->IELength += operation_len;10871088rtw_check_for_vht20(padapter, pnetwork->IEs + _BEACON_IE_OFFSET_, pnetwork->IELength - _BEACON_IE_OFFSET_);10891090pmlmepriv->vhtpriv.vht_option = _TRUE;1091}10921093void rtw_vht_ies_detach(_adapter *padapter, WLAN_BSSID_EX *pnetwork)1094{1095struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);10961097rtw_remove_bcn_ie(padapter, pnetwork, EID_EXTCapability);1098rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTCapability);1099rtw_remove_bcn_ie(padapter, pnetwork, EID_VHTOperation);11001101pmlmepriv->vhtpriv.vht_option = _FALSE;1102}11031104void rtw_check_for_vht20(_adapter *adapter, u8 *ies, int ies_len)1105{1106u8 ht_ch, ht_bw, ht_offset;1107u8 vht_ch, vht_bw, vht_offset;11081109rtw_ies_get_chbw(ies, ies_len, &ht_ch, &ht_bw, &ht_offset, 1, 0);1110rtw_ies_get_chbw(ies, ies_len, &vht_ch, &vht_bw, &vht_offset, 1, 1);11111112if (ht_bw == CHANNEL_WIDTH_20 && vht_bw >= CHANNEL_WIDTH_80) {1113u8 *vht_op_ie;1114int vht_op_ielen;11151116RTW_INFO(FUNC_ADPT_FMT" vht80 is not allowed without ht40\n", FUNC_ADPT_ARG(adapter));1117vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len);1118if (vht_op_ie && vht_op_ielen) {1119RTW_INFO(FUNC_ADPT_FMT" switch to vht20\n", FUNC_ADPT_ARG(adapter));1120SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);1121SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);1122SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);1123}1124}1125}1126#endif /* CONFIG_80211AC_VHT */112711281129