rtl8188eu/core/rtw_rm_util.c

502 lines
11 KiB
C

/******************************************************************************
*
* Copyright(c) 2007 - 2019 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#include <drv_types.h>
#include <hal_data.h>
#ifdef CONFIG_RTW_80211K
#include "rtw_rm_fsm.h"
#include "rtw_rm_util.h"
/* 802.11-2012 Table E-1 Operationg classes in United States */
static RT_OPERATING_CLASS RTW_OP_CLASS_US[] = {
/* 0, OP_CLASS_NULL */ { 0, 0, {}},
/* 1, OP_CLASS_1 */ {115, 4, {36, 40, 44, 48}},
/* 2, OP_CLASS_2 */ {118, 4, {52, 56, 60, 64}},
/* 3, OP_CLASS_3 */ {124, 4, {149, 153, 157, 161}},
/* 4, OP_CLASS_4 */ {121, 11, {100, 104, 108, 112, 116, 120, 124,
128, 132, 136, 140}},
/* 5, OP_CLASS_5 */ {125, 5, {149, 153, 157, 161, 165}},
/* 6, OP_CLASS_12 */ { 81, 11, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}
};
u8 rm_get_ch_set(
struct rtw_ieee80211_channel *pch_set, u8 op_class, u8 ch_num)
{
int i,j,sz;
u8 ch_amount = 0;
sz = sizeof(RTW_OP_CLASS_US)/sizeof(struct _RT_OPERATING_CLASS);
if (ch_num != 0) {
pch_set[0].hw_value = ch_num;
ch_amount = 1;
RTW_INFO("RM: meas_ch->hw_value = %u\n", pch_set->hw_value);
goto done;
}
for (i = 0; i < sz; i++) {
if (RTW_OP_CLASS_US[i].global_op_class == op_class) {
for (j = 0; j < RTW_OP_CLASS_US[i].Len; j++) {
pch_set[j].hw_value =
RTW_OP_CLASS_US[i].Channel[j];
RTW_INFO("RM: meas_ch[%d].hw_value = %u\n",
j, pch_set[j].hw_value);
}
ch_amount = RTW_OP_CLASS_US[i].Len;
break;
}
}
done:
return ch_amount;
}
u8 rm_get_ch_set_from_bcn_req_opt(
struct rtw_ieee80211_channel *pch_set, struct bcn_req_opt *opt)
{
int i,j,k,sz;
struct _RT_OPERATING_CLASS *ap_ch_rpt;
u8 ch_amount = 0;
k = 0;
for (i = 0; i < opt->ap_ch_rpt_num; i++) {
if (opt->ap_ch_rpt[i] == NULL)
break;
ap_ch_rpt = opt->ap_ch_rpt[i];
for (j = 0; j < ap_ch_rpt->Len; j++) {
pch_set[k].hw_value =
ap_ch_rpt->Channel[j];
RTW_INFO("RM: meas_ch[%d].hw_value = %u\n",
j, pch_set[k].hw_value);
k++;
}
}
return k;
}
u8 rm_get_oper_class_via_ch(u8 ch)
{
int i,j,sz;
sz = sizeof(RTW_OP_CLASS_US)/sizeof(struct _RT_OPERATING_CLASS);
for (i = 0; i < sz; i++) {
for (j = 0; j < RTW_OP_CLASS_US[i].Len; j++) {
if ( ch == RTW_OP_CLASS_US[i].Channel[j]) {
RTW_INFO("RM: ch %u in oper_calss %u\n",
ch, RTW_OP_CLASS_US[i].global_op_class);
return RTW_OP_CLASS_US[i].global_op_class;
break;
}
}
}
return 0;
}
int is_wildcard_bssid(u8 *bssid)
{
int i;
u8 val8 = 0xff;
for (i=0;i<6;i++)
val8 &= bssid[i];
if (val8 == 0xff)
return _SUCCESS;
return _FALSE;
}
u8 translate_dbm_to_rcpi(s8 SignalPower)
{
/* RCPI = Int{(Power in dBm + 110)*2} for 0dBm > Power > -110dBm
* 0 : power <= -110.0 dBm
* 1 : power = -109.5 dBm
* 2 : power = -109.0 dBm
*/
return (SignalPower + 110)*2;
}
u8 translate_percentage_to_rcpi(u32 SignalStrengthIndex)
{
/* Translate to dBm (x=y-100) */
return translate_dbm_to_rcpi(SignalStrengthIndex - 100);
}
u8 rm_get_bcn_rcpi(struct rm_obj *prm, struct wlan_network *pnetwork)
{
return translate_percentage_to_rcpi(
pnetwork->network.PhyInfo.SignalStrength);
}
u8 rm_get_frame_rsni(struct rm_obj *prm, union recv_frame *pframe)
{
int i;
u8 val8, snr, rx_num;
struct hal_spec_t *hal_spec = GET_HAL_SPEC(prm->psta->padapter);
if (IS_CCK_RATE((hw_rate_to_m_rate(pframe->u.hdr.attrib.data_rate))))
val8 = 255;
else {
snr = rx_num = 0;
for (i = 0; i < hal_spec->rf_reg_path_num; i++) {
if (GET_HAL_RX_PATH_BMP(prm->psta->padapter) & BIT(i)) {
snr += pframe->u.hdr.attrib.phy_info.rx_snr[i];
rx_num++;
}
}
snr = snr / rx_num;
val8 = (u8)(snr + 10)*2;
}
return val8;
}
u8 rm_get_bcn_rsni(struct rm_obj *prm, struct wlan_network *pnetwork)
{
int i;
u8 val8, snr, rx_num;
struct hal_spec_t *hal_spec = GET_HAL_SPEC(prm->psta->padapter);
if (pnetwork->network.PhyInfo.is_cck_rate) {
/* current HW doesn't have CCK RSNI */
/* 255 indicates RSNI is unavailable */
val8 = 255;
} else {
snr = rx_num = 0;
for (i = 0; i < hal_spec->rf_reg_path_num; i++) {
if (GET_HAL_RX_PATH_BMP(prm->psta->padapter) & BIT(i)) {
snr += pnetwork->network.PhyInfo.rx_snr[i];
rx_num++;
}
}
snr = snr / rx_num;
val8 = (u8)(snr + 10)*2;
}
return val8;
}
/* output: pwr (unit dBm) */
int rm_get_tx_power(PADAPTER adapter, enum rf_path path, enum MGN_RATE rate, s8 *pwr)
{
struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
int tx_num, band, bw, ch, n, rs;
u8 base;
s8 limt_offset = 127; /* max value of s8 */
s8 rate_offset;
s8 powr_offset;
int rate_pos;
band = hal_data->current_band_type;
bw = hal_data->current_channel_bw;
ch = hal_data->current_channel;
if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path))
return -1;
if (HAL_IsLegalChannel(adapter, ch) == _FALSE) {
RTW_INFO("Illegal channel!!\n");
return -2;
}
*pwr = phy_get_tx_power_final_absolute_value(adapter, path, rate, bw, ch);
return 0;
}
int rm_get_rx_sensitivity(PADAPTER adapter, enum channel_width bw, enum MGN_RATE rate, s8 *pwr)
{
s8 rx_sensitivity = -110;
switch(rate) {
case MGN_1M:
rx_sensitivity= -101;
break;
case MGN_2M:
rx_sensitivity= -98;
break;
case MGN_5_5M:
rx_sensitivity= -92;
break;
case MGN_11M:
rx_sensitivity= -89;
break;
case MGN_6M:
case MGN_9M:
case MGN_12M:
rx_sensitivity = -92;
break;
case MGN_18M:
rx_sensitivity = -90;
break;
case MGN_24M:
rx_sensitivity = -88;
break;
case MGN_36M:
rx_sensitivity = -84;
break;
case MGN_48M:
rx_sensitivity = -79;
break;
case MGN_54M:
rx_sensitivity = -78;
break;
case MGN_MCS0:
case MGN_MCS8:
case MGN_MCS16:
case MGN_MCS24:
case MGN_VHT1SS_MCS0:
case MGN_VHT2SS_MCS0:
case MGN_VHT3SS_MCS0:
case MGN_VHT4SS_MCS0:
/* BW20 BPSK 1/2 */
rx_sensitivity = -82;
break;
case MGN_MCS1:
case MGN_MCS9:
case MGN_MCS17:
case MGN_MCS25:
case MGN_VHT1SS_MCS1:
case MGN_VHT2SS_MCS1:
case MGN_VHT3SS_MCS1:
case MGN_VHT4SS_MCS1:
/* BW20 QPSK 1/2 */
rx_sensitivity = -79;
break;
case MGN_MCS2:
case MGN_MCS10:
case MGN_MCS18:
case MGN_MCS26:
case MGN_VHT1SS_MCS2:
case MGN_VHT2SS_MCS2:
case MGN_VHT3SS_MCS2:
case MGN_VHT4SS_MCS2:
/* BW20 QPSK 3/4 */
rx_sensitivity = -77;
break;
case MGN_MCS3:
case MGN_MCS11:
case MGN_MCS19:
case MGN_MCS27:
case MGN_VHT1SS_MCS3:
case MGN_VHT2SS_MCS3:
case MGN_VHT3SS_MCS3:
case MGN_VHT4SS_MCS3:
/* BW20 16-QAM 1/2 */
rx_sensitivity = -74;
break;
case MGN_MCS4:
case MGN_MCS12:
case MGN_MCS20:
case MGN_MCS28:
case MGN_VHT1SS_MCS4:
case MGN_VHT2SS_MCS4:
case MGN_VHT3SS_MCS4:
case MGN_VHT4SS_MCS4:
/* BW20 16-QAM 3/4 */
rx_sensitivity = -70;
break;
case MGN_MCS5:
case MGN_MCS13:
case MGN_MCS21:
case MGN_MCS29:
case MGN_VHT1SS_MCS5:
case MGN_VHT2SS_MCS5:
case MGN_VHT3SS_MCS5:
case MGN_VHT4SS_MCS5:
/* BW20 64-QAM 2/3 */
rx_sensitivity = -66;
break;
case MGN_MCS6:
case MGN_MCS14:
case MGN_MCS22:
case MGN_MCS30:
case MGN_VHT1SS_MCS6:
case MGN_VHT2SS_MCS6:
case MGN_VHT3SS_MCS6:
case MGN_VHT4SS_MCS6:
/* BW20 64-QAM 3/4 */
rx_sensitivity = -65;
break;
case MGN_MCS7:
case MGN_MCS15:
case MGN_MCS23:
case MGN_MCS31:
case MGN_VHT1SS_MCS7:
case MGN_VHT2SS_MCS7:
case MGN_VHT3SS_MCS7:
case MGN_VHT4SS_MCS7:
/* BW20 64-QAM 5/6 */
rx_sensitivity = -64;
break;
case MGN_VHT1SS_MCS8:
case MGN_VHT2SS_MCS8:
case MGN_VHT3SS_MCS8:
case MGN_VHT4SS_MCS8:
/* BW20 256-QAM 3/4 */
rx_sensitivity = -59;
break;
case MGN_VHT1SS_MCS9:
case MGN_VHT2SS_MCS9:
case MGN_VHT3SS_MCS9:
case MGN_VHT4SS_MCS9:
/* BW20 256-QAM 5/6 */
rx_sensitivity = -57;
break;
default:
return -1;
break;
}
switch(bw) {
case CHANNEL_WIDTH_20:
break;
case CHANNEL_WIDTH_40:
rx_sensitivity -= 3;
break;
case CHANNEL_WIDTH_80:
rx_sensitivity -= 6;
break;
case CHANNEL_WIDTH_160:
rx_sensitivity -= 9;
break;
case CHANNEL_WIDTH_5:
case CHANNEL_WIDTH_10:
case CHANNEL_WIDTH_80_80:
default:
return -1;
break;
}
*pwr = rx_sensitivity;
return 0;
}
/* output: path_a max tx power in dBm */
int rm_get_path_a_max_tx_power(_adapter *adapter, s8 *path_a)
{
struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
int path, tx_num, band, bw, ch, n, rs;
u8 rate_num;
s8 max_pwr[RF_PATH_MAX], pwr;
band = hal_data->current_band_type;
bw = hal_data->current_channel_bw;
ch = hal_data->current_channel;
for (path = 0; path < RF_PATH_MAX; path++) {
if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path))
break;
max_pwr[path] = -127; /* min value of s8 */
#if (RM_MORE_DBG_MSG)
RTW_INFO("RM: [%s][%c]\n", band_str(band), rf_path_char(path));
#endif
for (rs = 0; rs < RATE_SECTION_NUM; rs++) {
tx_num = rate_section_to_tx_num(rs);
if (tx_num >= hal_spec->tx_nss_num)
continue;
if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs))
continue;
if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_ALL(adapter))
continue;
rate_num = rate_section_rate_num(rs);
/* get power by rate in db */
for (n = rate_num - 1; n >= 0; n--) {
pwr = phy_get_tx_power_final_absolute_value(adapter, path, rates_by_sections[rs].rates[n], bw, ch);
max_pwr[path] = MAX(max_pwr[path], pwr);
#if (RM_MORE_DBG_MSG)
RTW_INFO("RM: %9s = %2d\n",
MGN_RATE_STR(rates_by_sections[rs].rates[n]), pwr);
#endif
}
}
}
#if (RM_MORE_DBG_MSG)
RTW_INFO("RM: path_a max_pwr=%ddBm\n", max_pwr[0]);
#endif
*path_a = max_pwr[0];
return 0;
}
u8 rm_gen_dialog_token(_adapter *padapter)
{
struct rm_priv *prmpriv = &(padapter->rmpriv);
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
do {
pmlmeinfo->dialogToken++;
} while (pmlmeinfo->dialogToken == 0);
return pmlmeinfo->dialogToken;
}
u8 rm_gen_meas_token(_adapter *padapter)
{
struct rm_priv *prmpriv = &(padapter->rmpriv);
do {
prmpriv->meas_token++;
} while (prmpriv->meas_token == 0);
return prmpriv->meas_token;
}
u32 rm_gen_rmid(_adapter *padapter, struct rm_obj *prm, u8 role)
{
u32 rmid;
if (prm->psta == NULL)
goto err;
if (prm->q.diag_token == 0)
goto err;
rmid = prm->psta->cmn.aid << 16
| prm->q.diag_token << 8
| role;
return rmid;
err:
RTW_ERR("RM: unable to gen rmid\n");
return 0;
}
#endif /* CONFIG_RTW_80211K */