/****************************************************************************** * * Copyright(c) 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 "halbb_precomp.h" #ifdef HALBB_RA_SUPPORT const u16 bb_phy_rate_table[] = { /*CCK*/ 1, 2, 5, 11, /*OFDM*/ 6, 9, 12, 18, 24, 36, 48, 54, /*HT/VHT-1ss LGI*/ 6, 13, 19, 26, 39, 52, 58, 65, 78, 87, 98, 108, /*HT/VHT-2ss LGI*/ 13, 26, 39, 52, 78, 104, 117, 130, 156, 173, 195, 217, /*HT/VHT-3ss LGI*/ 19, 39, 58, 78, 117, 156, 175, 195, 234, 260, 293, 325, /*HT/VHT-4ss LGI*/ 26, 52, 78, 104, 156, 208, 234, 260, 312, 347, 390, 433, }; /*HE[3.2] = VHT[LGI] * 1.125*/ bool halbb_is_he_rate(struct bb_info *bb, u16 rate) { return ((((rate & 0x1ff) >= BB_HE_1SS_MCS0) && ((rate & 0x1ff) <= BB_HE_1SS_MCS(11))) || (((rate & 0x1ff) >= BB_HE_2SS_MCS0) && ((rate & 0x1ff) <= BB_HE_2SS_MCS(11))) || (((rate & 0x1ff) >= BB_HE_3SS_MCS0) && ((rate & 0x1ff) <= BB_HE_3SS_MCS(11))) || (((rate & 0x1ff) >= BB_HE_4SS_MCS0) && ((rate & 0x1ff) <= BB_HE_4SS_MCS(11)))) ? true : false; } bool halbb_is_vht_rate(struct bb_info *bb, u16 rate) { return ((((rate & 0x1ff) >= BB_VHT_1SS_MCS0) && ((rate & 0x1ff) <= BB_VHT_1SS_MCS(9))) || (((rate & 0x1ff) >= BB_VHT_2SS_MCS0) && ((rate & 0x1ff) <= BB_VHT_2SS_MCS(9))) || (((rate & 0x1ff) >= BB_VHT_3SS_MCS0) && ((rate & 0x1ff) <= BB_VHT_3SS_MCS(9))) || (((rate & 0x1ff) >= BB_VHT_4SS_MCS0) && ((rate & 0x1ff) <= BB_VHT_4SS_MCS(9)))) ? true : false; } bool halbb_is_ht_rate(struct bb_info *bb, u16 rate) { return (((rate & 0x1ff) >= BB_HT_MCS0) && ((rate & 0x1ff) <= BB_HT_MCS(31))) ? true : false; } bool halbb_is_ofdm_rate(struct bb_info *bb, u16 rate) { return (((rate & 0x1ff) >= BB_06M) && ((rate & 0x1ff) <= BB_54M)) ? true : false; } bool halbb_is_cck_rate(struct bb_info *bb, u16 rate) { return ((rate & 0x1ff) <= BB_11M) ? true : false; } u8 halbb_legacy_rate_2_spec_rate(struct bb_info *bb, u16 rate) { u8 rate_idx = 0x0; u8 legacy_spec_rate_t[8] = {BB_SPEC_RATE_6M, BB_SPEC_RATE_9M, BB_SPEC_RATE_12M, BB_SPEC_RATE_18M, BB_SPEC_RATE_24M, BB_SPEC_RATE_36M, BB_SPEC_RATE_48M, BB_SPEC_RATE_54M}; rate_idx = rate - BB_06M; return legacy_spec_rate_t[rate_idx]; } u8 halbb_mgnt_2_hw_rate(u8 rate) { u8 ret = 0; /*exclude BSS basic bit*/ rate &= 0x7f; /*a/b/g mode only, there is no requirement for n/ac/ax mode*/ if (rate > 108) return ret; /*unit:0.5Mbps*/ switch (rate) { case 2: ret = BB_01M; break; case 4: ret = BB_02M; break; case 11: ret = BB_05M; break; case 22: ret = BB_11M; break; case 12: ret = BB_06M; break; case 18: ret = BB_09M; break; case 24: ret = BB_12M; break; case 36: ret = BB_18M; break; case 48: ret = BB_24M; break; case 72: ret = BB_36M; break; case 96: ret = BB_48M; break; case 108: ret = BB_54M; break; default: break; } return ret; } u8 halbb_mcs_ss_to_fw_rate_idx(u8 mode, u8 mcs, u8 ss) { u8 fw_rate_idx = 0; if (mode == 3) { fw_rate_idx = RATE_HE1SS_MCS0 + (ss - 1) * 12; // MAX HE MCS is MCS11 (Totally, 12 MCS index) } else if (mode == 2) { fw_rate_idx = RATE_VHT1SS_MCS0 + (ss - 1) * 10; // MAX VHT MCS is MCS9 (Totally, 10 MCS index) } else if (mode == 1) { // HT fw_rate_idx = RATE_HT_MCS0 + (ss - 1) * 8; } else { fw_rate_idx = 0; } return fw_rate_idx; } void halbb_rate_idx_parsor(struct bb_info *bb, u16 rate_idx, enum rtw_gi_ltf gi_ltf, struct bb_rate_info *ra_i) { ra_i->rate_idx_all = rate_idx | (((u16)gi_ltf & 0xf) << 12); ra_i->rate_idx = rate_idx; ra_i->gi_ltf = gi_ltf; ra_i->mode = (enum bb_mode_type)((rate_idx & 0x180) >> 7); if (ra_i->mode == BB_LEGACY_MODE) { ra_i->ss = 1; ra_i->idx = rate_idx & 0x1f; } else if (ra_i->mode == BB_HT_MODE) { ra_i->ss = (ra_i->idx >> 3) + 1; ra_i->idx = rate_idx & 0x1f; } else { ra_i->ss = ((rate_idx & 0x70) >> 4) + 1; ra_i->idx = rate_idx & 0xf; } /* Transfer to fw used rate_idx*/ if (ra_i->mode == BB_LEGACY_MODE) { ra_i->fw_rate_idx = ra_i->idx; return; } ra_i->fw_rate_idx = halbb_mcs_ss_to_fw_rate_idx(ra_i->mode, ra_i->idx, ra_i->ss); return; } u8 halbb_rate_2_rate_digit(struct bb_info *bb, u16 rate) { u8 legacy_table[12] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; u8 rate_digit = 0; if (rate >= BB_HE_8SS_MCS0) rate_digit = (rate - BB_HE_8SS_MCS0); else if (rate >= BB_HE_7SS_MCS0) rate_digit = (rate - BB_HE_7SS_MCS0); else if (rate >= BB_HE_6SS_MCS0) rate_digit = (rate - BB_HE_6SS_MCS0); else if (rate >= BB_HE_5SS_MCS0) rate_digit = (rate - BB_HE_5SS_MCS0); else if (rate >= BB_HE_4SS_MCS0) rate_digit = (rate - BB_HE_4SS_MCS0); else if (rate >= BB_HE_3SS_MCS0) rate_digit = (rate - BB_HE_3SS_MCS0); else if (rate >= BB_HE_2SS_MCS0) rate_digit = (rate - BB_HE_2SS_MCS0); else if (rate >= BB_HE_1SS_MCS0) rate_digit = (rate - BB_HE_1SS_MCS0); else if (rate >= BB_VHT_8SS_MCS0) rate_digit = (rate - BB_VHT_8SS_MCS0); else if (rate >= BB_VHT_7SS_MCS0) rate_digit = (rate - BB_VHT_7SS_MCS0); else if (rate >= BB_VHT_6SS_MCS0) rate_digit = (rate - BB_VHT_6SS_MCS0); else if (rate >= BB_VHT_5SS_MCS0) rate_digit = (rate - BB_VHT_5SS_MCS0); else if (rate >= BB_VHT_4SS_MCS0) rate_digit = (rate - BB_VHT_4SS_MCS0); else if (rate >= BB_VHT_3SS_MCS0) rate_digit = (rate - BB_VHT_3SS_MCS0); else if (rate >= BB_VHT_2SS_MCS0) rate_digit = (rate - BB_VHT_2SS_MCS0); else if (rate >= BB_VHT_1SS_MCS0) rate_digit = (rate - BB_VHT_1SS_MCS0); else if (rate >= BB_HT_MCS0) rate_digit = (rate - BB_HT_MCS0); else if (rate <= BB_54M) rate_digit = legacy_table[rate]; return rate_digit; } /*u8 halbb_get_rx_stream_num(struct bb_info *bb, enum rf_type type) { u8 rx_num = 1; if (type == RF_1T1R) rx_num = 1; else if (type == RF_2T2R || type == RF_1T2R) rx_num = 2; else if (type == RF_3T3R || type == RF_2T3R) rx_num = 3; else if (type == RF_4T4R || type == RF_3T4R || type == RF_2T4R) rx_num = 4; else BB_WARNING("%s\n", __func__); return rx_num; }*/ u8 halbb_rate_type_2_num_ss(struct bb_info *bb, enum halbb_rate_type type) { u8 num_ss = 1; switch (type) { case BB_CCK: case BB_OFDM: case BB_1SS: num_ss = 1; break; case BB_2SS: num_ss = 2; break; case BB_3SS: num_ss = 3; break; case BB_4SS: num_ss = 4; break; default: break; } return num_ss; } u8 halbb_rate_to_num_ss(struct bb_info *bb, u16 rate) { u8 num_ss = 1; if (rate <= BB_54M) num_ss = 1; else if (rate <= BB_HT_MCS(31)) num_ss = ((rate - BB_HT_MCS0) >> 3) + 1; else if (rate <= BB_VHT_1SS_MCS(9)) num_ss = 1; else if (rate <= BB_VHT_2SS_MCS(9)) num_ss = 2; else if (rate <= BB_VHT_3SS_MCS(9)) num_ss = 3; else if (rate <= BB_VHT_4SS_MCS(9)) num_ss = 4; else if (rate <= BB_VHT_5SS_MCS(9)) num_ss = 5; else if (rate <= BB_VHT_6SS_MCS(9)) num_ss = 6; else if (rate <= BB_VHT_7SS_MCS(9)) num_ss = 7; else if (rate <= BB_VHT_8SS_MCS(9)) num_ss = 8; else if (rate <= BB_HE_1SS_MCS(11)) num_ss = 1; else if (rate <= BB_HE_2SS_MCS(11)) num_ss = 2; else if (rate <= BB_HE_3SS_MCS(11)) num_ss = 3; else if (rate <= BB_HE_4SS_MCS(11)) num_ss = 4; else if (rate <= BB_HE_5SS_MCS(11)) num_ss = 5; else if (rate <= BB_HE_6SS_MCS(11)) num_ss = 6; else if (rate <= BB_HE_7SS_MCS(11)) num_ss = 7; else if (rate <= BB_HE_8SS_MCS(11)) num_ss = 8; return num_ss; } void halbb_print_rate_2_buff(struct bb_info *bb, u16 rate_idx, enum rtw_gi_ltf gi_ltf, char *buf, u16 buf_size) { struct bb_rate_info rate; char *ss = NULL; char *mode = NULL; char *gi = NULL; halbb_rate_idx_parsor(bb, rate_idx, gi_ltf, &rate); if (rate.mode == BB_HE_MODE) mode = "HE "; else if (rate.mode == BB_VHT_MODE) mode = "VHT "; else if (rate.mode == BB_HT_MODE) mode = "HT"; else mode = ""; if (rate.ss == 4) ss = "4"; else if (rate.ss == 3) ss = "3"; else if (rate.ss == 2) ss = "2"; else ss = "1"; if (rate.mode == BB_HE_MODE) { if (rate.gi_ltf == RTW_GILTF_LGI_4XHE32) gi = "[4X32]"; else if (rate.gi_ltf == RTW_GILTF_SGI_4XHE08) gi = "[4X08]"; else if (rate.gi_ltf == RTW_GILTF_2XHE16) gi = "[2X16]"; else if (rate.gi_ltf == RTW_GILTF_2XHE08) gi = "[2X08]"; else if (rate.gi_ltf == RTW_GILTF_1XHE16) gi = "[1X16]"; else gi = "[1X08]"; } else if (rate.mode >= BB_HT_MODE) { if (rate.gi_ltf == RTW_GILTF_SGI_4XHE08) gi = "[sgi]"; else gi = ""; } else { gi = ""; } /* BB_SNPRINTF wait driver porting */ _os_snprintf(buf, buf_size, "(%s%s%s%s%d%s%s)", mode, (rate.mode >= BB_VHT_MODE) ? ss : "", (rate.mode >= BB_VHT_MODE) ? "-ss " : "", (rate.rate_idx >= BB_HT_MCS0) ? "MCS" : "", (rate.rate_idx >= BB_HT_MCS0) ? rate.idx : bb_phy_rate_table[rate.idx], gi, (rate.rate_idx < BB_HT_MCS0) ? "M" : ""); } enum bb_qam_type halbb_get_qam_order(struct bb_info *bb, u16 rate_idx) { u16 tmp_idx = rate_idx; enum bb_qam_type qam_order = BB_QAM_BPSK; enum bb_qam_type qam[10] = {BB_QAM_BPSK, BB_QAM_QPSK, BB_QAM_QPSK, BB_QAM_16QAM, BB_QAM_16QAM, BB_QAM_64QAM, BB_QAM_64QAM, BB_QAM_64QAM, BB_QAM_256QAM, BB_QAM_256QAM}; if (rate_idx <= BB_11M) return BB_QAM_CCK; if ((rate_idx >= BB_VHT_MCS(1, 0)) && (rate_idx <= BB_VHT_MCS(4, 9))) { if (rate_idx >= BB_VHT_MCS(4, 0)) tmp_idx -= BB_VHT_MCS(4, 0); else if (rate_idx >= BB_VHT_MCS(3, 0)) tmp_idx -= BB_VHT_MCS(3, 0); else if (rate_idx >= BB_VHT_MCS(2, 0)) tmp_idx -= BB_VHT_MCS(2, 0); else tmp_idx -= BB_VHT_MCS(1, 0); qam_order = qam[tmp_idx]; } else if ((rate_idx >= BB_HT_MCS(0)) && (rate_idx <= BB_HT_MCS(31))) { if (rate_idx >= BB_HT_MCS(24)) tmp_idx -= BB_HT_MCS(24); else if (rate_idx >= BB_HT_MCS(16)) tmp_idx -= BB_HT_MCS(16); else if (rate_idx >= BB_HT_MCS(8)) tmp_idx -= BB_HT_MCS(8); else tmp_idx -= BB_HT_MCS(0); qam_order = qam[tmp_idx]; } else { if ((rate_idx > BB_06M) && (rate_idx <= BB_54M)) { tmp_idx -= BB_06M; qam_order = qam[tmp_idx - 1]; } else { /* OFDM 6M & all other undefine rate*/ qam_order = BB_QAM_BPSK; } } return qam_order; } u8 halbb_rate_order_compute(struct bb_info *bb, u16 rate_idx) { u16 rate_order = rate_idx & 0x7f; rate_idx &= 0x7f; if (rate_idx >= BB_VHT_MCS(4, 0)) rate_order -= BB_VHT_MCS(4, 0); else if (rate_idx >= BB_VHT_MCS(3, 0)) rate_order -= BB_VHT_MCS(3, 0); else if (rate_idx >= BB_VHT_MCS(2, 0)) rate_order -= BB_VHT_MCS(2, 0); else if (rate_idx >= BB_VHT_MCS(1, 0)) rate_order -= BB_VHT_MCS(1, 0); else if (rate_idx >= BB_HT_MCS(24)) rate_order -= BB_HT_MCS(24); else if (rate_idx >= BB_HT_MCS(16)) rate_order -= BB_HT_MCS(16); else if (rate_idx >= BB_HT_MCS(8)) rate_order -= BB_HT_MCS(8); else if (rate_idx >= BB_HT_MCS(0)) rate_order -= BB_HT_MCS(0); else if (rate_idx >= BB_06M) rate_order -= BB_06M; else rate_order -= BB_01M; if (rate_idx >= BB_HT_MCS(0)) rate_order++; return (u8)rate_order; } u8 halbb_init_ra_by_rssi(struct bb_info *bb, u8 rssi_assoc) { u8 init_ra_lv = 0; BB_DBG(bb, DBG_RA, "====>%s\n", __func__); if (rssi_assoc > 50) init_ra_lv = 1; else if (rssi_assoc > 30) init_ra_lv = 2; else if (rssi_assoc > 1) init_ra_lv = 3; else init_ra_lv = 0; return init_ra_lv; } bool halbb_set_csi_rate(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { u8 macid; struct bb_h2c_ra_cfg_info *ra_cfg; struct rtw_hal_stainfo_t *hal_sta_i; struct rtw_ra_sta_info * ra_sta_i; if (!phl_sta_i || !bb) return false; macid = (u8)(phl_sta_i->macid); hal_sta_i = phl_sta_i->hal_sta; if (!hal_sta_i) return false; ra_cfg = &bb->bb_ra_i[macid].ra_cfg; ra_sta_i = &(hal_sta_i->ra_info); if (!ra_sta_i) return false; /*if ((!ra_sta_i->ra_csi_rate_en) && (!ra_sta_i->fixed_csi_rate_en)) return false;*/ /* Set csi rate ctrl enable */ ra_cfg->ramask[7] |= BIT(7); ra_cfg->ra_csi_rate_en = ra_sta_i->ra_csi_rate_en; ra_cfg->fixed_csi_rate_en = ra_sta_i->fixed_csi_rate_en; ra_cfg->cr_tbl_sel = bb->hal_com->csi_para_ctrl_sel; ra_cfg->band_num = ra_sta_i->band_num; ra_cfg->fixed_csi_rate_l = ra_sta_i->csi_rate.mcs_ss_idx; ra_cfg->fixed_csi_rate_m = ra_sta_i->csi_rate.mode | ra_sta_i->csi_rate.gi_ltf << 2 | ra_sta_i->csi_rate.bw << 5; return true; } u8 halbb_rssi_lv_dec(struct bb_info *bb, u8 rssi, u8 ratr_state) { /*@MCS0 ~ MCS4 , VHT1SS MCS0 ~ MCS4 , G 6M~24M*/ /*u8 rssi_lv_t[RA_FLOOR_TABLE_SIZE] = {20, 34, 38, 42, 46, 50, 100};*/ u8 rssi_lv_t[RA_FLOOR_TABLE_SIZE] = {30, 44, 48, 52, 56, 60, 100}; /*@ RSSI definition changed in AX*/ u8 new_rssi_lv = 0; u8 i; BB_DBG(bb, DBG_RA, "curr RA level=(%d), Table_ori=[%d, %d, %d, %d, %d, %d]\n", ratr_state, rssi_lv_t[0], rssi_lv_t[1], rssi_lv_t[2], rssi_lv_t[3], rssi_lv_t[4], rssi_lv_t[5]); for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) { if (i >= (ratr_state)) rssi_lv_t[i] += RA_FLOOR_UP_GAP; } BB_DBG(bb, DBG_RA, "RSSI=(%d), Table_mod=[%d, %d, %d, %d, %d, %d]\n", rssi, rssi_lv_t[0], rssi_lv_t[1], rssi_lv_t[2], rssi_lv_t[3], rssi_lv_t[4], rssi_lv_t[5]); for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) { if (rssi < rssi_lv_t[i]) { new_rssi_lv = i; break; } } return new_rssi_lv; } u64 halbb_ramask_by_rssi(struct bb_info *bb, u8 rssi_lv, u64 ramask) { u64 ra_mask_bitmap = ramask; if (rssi_lv == 0) ra_mask_bitmap &= 0xffffffffffffffff; else if (rssi_lv == 1) ra_mask_bitmap &= 0xfffffffffffffff0; else if (rssi_lv == 2) ra_mask_bitmap &= 0xffffffffffffefe0; else if (rssi_lv == 3) ra_mask_bitmap &= 0xffffffffffffcfc0; else if (rssi_lv == 4) ra_mask_bitmap &= 0xffffffffffff8f80; else if (rssi_lv >= 5) ra_mask_bitmap &= 0xffffffffffff0f00; /*Avoid empty HT/VHT/HE ramask when HT/VHT/HE mode is enabled*/ if ((ra_mask_bitmap >> 12) == 0x0) { ra_mask_bitmap |= (ramask & 0xfffffffffffff000); BB_DBG(bb, DBG_RA, "Empty HT/VHT/HE ramask! Bypass HT/VHT/HE ramask_by_rssi\n"); } /*Avoid empty legacy ramask after foolproof of HT/VHT/HE mode*/ if (ra_mask_bitmap == 0x0) { ra_mask_bitmap |= (ramask & 0xfff); BB_DBG(bb, DBG_RA, "Empty ramask! Bypass a/b/g ramask_by_rssi\n"); } return ra_mask_bitmap; } u64 halbb_ramask_mod(struct bb_info *bb, u8 macid, u64 ramask, u8 rssi, u8 mode, u8 nss) { struct bb_ra_info *bb_ra = &bb->bb_ra_i[macid]; u64 mod_mask = ramask; u64 mod_mask_rssi = ramask; u8 new_rssi_lv = 0; u8 wifi_mode = RA_non_ht; if (mode == CCK_SUPPORT) { /* B mode */ mod_mask &= RAMASK_B; wifi_mode = RA_CCK; BB_DBG(bb, DBG_RA, "RA mask B mode\n"); } else if (mode == OFDM_SUPPORT) { /* AG mode */ mod_mask &= RAMASK_AG; wifi_mode = RA_non_ht; BB_DBG(bb, DBG_RA, "RA mask A mode\n"); } else if (mode == (CCK_SUPPORT|OFDM_SUPPORT)) { /* BG mode */ mod_mask &= RAMASK_BG; wifi_mode = RA_non_ht; BB_DBG(bb, DBG_RA, "RA mask 2.4G BG mode\n"); } else if (mode == (CCK_SUPPORT|OFDM_SUPPORT|HT_SUPPORT)) { /* 2G N mode */ mod_mask &= RAMASK_HT_2G; wifi_mode = RA_HT; BB_DBG(bb, DBG_RA, "RA mask 2.4G HT mode\n"); } else if (mode == (OFDM_SUPPORT|HT_SUPPORT)) { /* 5G N mode */ mod_mask &= RAMASK_HT_5G; wifi_mode = RA_HT; BB_DBG(bb, DBG_RA, "RA mask 5G HT mode\n"); } else if (mode == (CCK_SUPPORT|OFDM_SUPPORT|VHT_SUPPORT_TX)) { /* 2G AC mode */ mod_mask &= RAMASK_VHT_2G; wifi_mode = RA_VHT; BB_DBG(bb, DBG_RA, "RA mask 2.4G VHT mode\n"); } else if (mode == (OFDM_SUPPORT|VHT_SUPPORT_TX)) { /* 5G AC mode */ mod_mask &= RAMASK_VHT_5G; wifi_mode = RA_VHT; BB_DBG(bb, DBG_RA, "RA mask 5G VHT mode\n"); } else if (mode == (CCK_SUPPORT|OFDM_SUPPORT|HE_SUPPORT)) { /* 2G AX mode */ mod_mask &= RAMASK_HE_2G; wifi_mode = RA_HE; BB_DBG(bb, DBG_RA, "RA mask 2.4G HE mode\n"); } else if (mode == (OFDM_SUPPORT|HE_SUPPORT)) { /* 5G AX mode */ mod_mask &= RAMASK_HE_5G; wifi_mode = RA_HE; BB_DBG(bb, DBG_RA, "RA mask 5G HE mode\n"); } else { BB_WARNING("MD id %x, RA mask not found\n", mode); } BB_DBG(bb, DBG_RA, "RA mask SS NUM : %d\n", nss); if (wifi_mode == RA_HT) { switch (nss) { case RA_1SS_MODE: mod_mask &= RAMASK_1SS_HT; break; case RA_2SS_MODE: mod_mask &= RAMASK_2SS_HT; break; case RA_3SS_MODE: mod_mask &= RAMASK_3SS_HT; break; case RA_4SS_MODE: mod_mask &= RAMASK_4SS_HT; break; default: mod_mask &= RAMASK_1SS_HT; break; } } else if (wifi_mode == RA_VHT) { switch (nss) { case RA_1SS_MODE: mod_mask &= RAMASK_1SS_VHT; break; case RA_2SS_MODE: mod_mask &= RAMASK_2SS_VHT; break; case RA_3SS_MODE: mod_mask &= RAMASK_3SS_VHT; break; case RA_4SS_MODE: mod_mask &= RAMASK_4SS_VHT; break; default: mod_mask &= RAMASK_1SS_VHT; break; } } else if (wifi_mode == RA_HE) { switch (nss) { case RA_1SS_MODE: mod_mask &= RAMASK_1SS_HE; break; case RA_2SS_MODE: mod_mask &= RAMASK_2SS_HE; break; case RA_3SS_MODE: mod_mask &= RAMASK_3SS_HE; break; case RA_4SS_MODE: mod_mask &= RAMASK_4SS_HE; break; default: mod_mask &= RAMASK_1SS_HE; break; } } else { BB_DBG(bb, DBG_RA, "RA mask non-ht mode\n"); } BB_DBG(bb, DBG_RA, "RA mask modify : %llx\n", mod_mask); new_rssi_lv = halbb_rssi_lv_dec(bb, rssi, bb_ra->rssi_lv); if (wifi_mode != RA_CCK) { mod_mask_rssi = halbb_ramask_by_rssi(bb, new_rssi_lv, mod_mask); //BB_DBG(bb, DBG_RA, "RA mask modify by rssi : 0x%016llx\n", mod_mask_rssi); } else { mod_mask_rssi = mod_mask; } return mod_mask_rssi; } void rtw_halbb_mudbg(struct bb_info *bb, u8 type, u8 mu_entry, u8 macid, bool en_256q, bool en_1024q) { struct bb_h2c_mu_cfg mucfg = {0}; u32 *bb_h2c = (u32 *)&mucfg; u8 cmdlen = sizeof(mucfg); mucfg.cmd_type = type; mucfg.entry = mu_entry; mucfg.macid = macid; halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_MUCFG, HALBB_H2C_RA, bb_h2c); } u64 halbb_gen_abg_mask(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { u64 tmp_mask = 0; u64 abg_mask = 0; u8 i; struct protocol_cap_t *asoc_cap_i; if (!phl_sta_i) return 0; asoc_cap_i = &phl_sta_i->asoc_cap; BB_DBG(bb, DBG_RA, "supported rates(L->H) = [%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x]\n", asoc_cap_i->supported_rates[0], asoc_cap_i->supported_rates[1], asoc_cap_i->supported_rates[2], asoc_cap_i->supported_rates[3], asoc_cap_i->supported_rates[4], asoc_cap_i->supported_rates[5], asoc_cap_i->supported_rates[6], asoc_cap_i->supported_rates[7], asoc_cap_i->supported_rates[8], asoc_cap_i->supported_rates[9], asoc_cap_i->supported_rates[10], asoc_cap_i->supported_rates[11]); for (i = 0; i < MAX_ABG_RATE_NUM; i++) { if (asoc_cap_i->supported_rates[i] == 0x0) continue; tmp_mask = (u64)halbb_mgnt_2_hw_rate(asoc_cap_i->supported_rates[i]); abg_mask |= (u64)BIT(tmp_mask); } BB_DBG(bb, DBG_RA, "gen_abgmask: 0x%llx\n", abg_mask); return abg_mask; } u64 halbb_gen_vht_mask(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { u8 vht_cap[2] = {0}; u8 tmp_cap = 0; u8 cap_ss; u64 tmp_mask_nss = 0; u8 i; struct protocol_cap_t *asoc_cap_i; /*@Becareful RA use our "Tx" capability which means the capability of their "Rx"*/ if (!phl_sta_i) return 0; asoc_cap_i = &phl_sta_i->asoc_cap; vht_cap[0] = asoc_cap_i->vht_rx_mcs[0]; vht_cap[1] = asoc_cap_i->vht_rx_mcs[1]; BB_DBG(bb, DBG_RA, "%s : vhtcap:%x %x\n", __func__, vht_cap[0], vht_cap[1]); for (i = 0; i < MAX_NSS_VHT; i++) { if (i == 0) tmp_cap = vht_cap[0]; else if (i == 4) tmp_cap = vht_cap[1]; cap_ss = tmp_cap & 0x03; tmp_cap = tmp_cap >> 2; if (cap_ss == 0) tmp_mask_nss |= ((u64)0xff << (i * 12)); else if (cap_ss == 1) tmp_mask_nss |= ((u64)0x1ff << (i * 12)); else if (cap_ss == 2) tmp_mask_nss |= ((u64)0x3ff << (i * 12)); BB_DBG(bb, DBG_RA, "gen_vhtmask:cap%x, ss%x, hemask: 0x%llx\n", cap_ss, i, tmp_mask_nss); } return tmp_mask_nss; } u64 halbb_gen_ht_mask(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { u8 ht_cap[4] = {0}; u64 cap_ss; u64 tmp_mask_nss = 0; u8 i; struct protocol_cap_t *asoc_cap_i; /*@Becareful RA use our "Tx" capability which means the capability of their "Rx"*/ if (!phl_sta_i) return 0; asoc_cap_i = &phl_sta_i->asoc_cap; for (i = 0; i < MAX_NSS_HT; i++)/* can use pointer after merge code*/ ht_cap[i] = asoc_cap_i->ht_rx_mcs[i]; BB_DBG(bb, DBG_RA, "%s : htcap: %x %x\n", __func__, ht_cap[0], ht_cap[1]); for (i = 0; i < MAX_NSS_HT; i++) { cap_ss = (u64)ht_cap[i]; tmp_mask_nss = tmp_mask_nss | (cap_ss << (i * 12)); BB_DBG(bb, DBG_RA, "gen_htmask:cap%llx, ss%x, htmask: 0x%llx\n", cap_ss, i, tmp_mask_nss); } return tmp_mask_nss; } u64 halbb_gen_he_mask(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i, enum channel_width bw) { u8 he_cap[2] = {0}; u8 tmp_cap = 0; u8 cap_ss; u64 tmp_mask_nss = 0; u8 i; struct protocol_cap_t *asoc_cap_i; /*@Becareful RA use our "Tx" capability which means the capability of their "Rx"*/ /*@In HE cap, mcs is correspond to channel bw"*/ if (!phl_sta_i) return 0; asoc_cap_i = &phl_sta_i->asoc_cap; if (bw == CHANNEL_WIDTH_80_80) { he_cap[0] = asoc_cap_i->he_rx_mcs[4]; he_cap[1] = asoc_cap_i->he_rx_mcs[5]; } else if (bw == CHANNEL_WIDTH_160) { he_cap[0] = asoc_cap_i->he_rx_mcs[2]; he_cap[1] = asoc_cap_i->he_rx_mcs[3]; } else { he_cap[0] = asoc_cap_i->he_rx_mcs[0]; he_cap[1] = asoc_cap_i->he_rx_mcs[1]; } BB_DBG(bb, DBG_RA, "%s: hecap:%x %x\n", __func__, he_cap[0], he_cap[1]); for (i = 0; i < MAX_NSS_HE; i++) { if (i == 0) tmp_cap = he_cap[0]; else if (i == 4) tmp_cap = he_cap[1]; cap_ss = tmp_cap & 0x03; tmp_cap = tmp_cap >> 2; if (cap_ss == 0) tmp_mask_nss |= ((u64)0xff << (i * 12)); else if (cap_ss == 1) tmp_mask_nss |= ((u64)0x3ff << (i * 12)); else if (cap_ss == 2) tmp_mask_nss |= ((u64)0xfff << (i * 12)); BB_DBG(bb, DBG_RA, "gen_hemask:cap%x, ss%x, hemask: 0x%llx\n", cap_ss, i, tmp_mask_nss); } return tmp_mask_nss; } bool halbb_chk_bw_under_20(struct bb_info *bb, u8 bw) { bool ret_val = true; switch (bw) { case CHANNEL_WIDTH_5: case CHANNEL_WIDTH_10: case CHANNEL_WIDTH_20: ret_val = true; break; case CHANNEL_WIDTH_40: case CHANNEL_WIDTH_80: case CHANNEL_WIDTH_80_80: case CHANNEL_WIDTH_160: ret_val = false; break; default: ret_val = false; break; } return ret_val; } bool halbb_chk_bw_under_40(struct bb_info *bb, u8 bw) { bool ret_val = true; switch (bw) { case CHANNEL_WIDTH_5: case CHANNEL_WIDTH_10: case CHANNEL_WIDTH_20: case CHANNEL_WIDTH_40: ret_val = true; break; case CHANNEL_WIDTH_80: case CHANNEL_WIDTH_80_80: case CHANNEL_WIDTH_160: ret_val = false; break; default: ret_val = false; break; } return ret_val; } bool halbb_hw_bw_mode_chk(struct bb_info *bb, u8 bw, u8 hw_mode) { bool ret_val = true; switch (hw_mode) { case CCK_SUPPORT: case OFDM_SUPPORT: case (CCK_SUPPORT | OFDM_SUPPORT): ret_val = halbb_chk_bw_under_20(bb, bw); break; case HT_SUPPORT: case (HT_SUPPORT | CCK_SUPPORT): case (HT_SUPPORT | OFDM_SUPPORT): case (HT_SUPPORT | OFDM_SUPPORT | CCK_SUPPORT): ret_val = halbb_chk_bw_under_40(bb, bw); break; case VHT_SUPPORT_TX: case (VHT_SUPPORT_TX | CCK_SUPPORT): case (VHT_SUPPORT_TX | OFDM_SUPPORT): case (VHT_SUPPORT_TX | OFDM_SUPPORT | CCK_SUPPORT): case HE_SUPPORT: case (HE_SUPPORT | CCK_SUPPORT): case (HE_SUPPORT | OFDM_SUPPORT): case (HE_SUPPORT | OFDM_SUPPORT | CCK_SUPPORT): ret_val = true; break; default: ret_val = true; break; } if (!ret_val) BB_WARNING("WRONG BW setting !!!!\n"); return ret_val; } u8 halbb_hw_bw_mapping(struct bb_info *bb, u8 bw, u8 hw_mode) { u8 hw_bw_map = CHANNEL_WIDTH_20; bool ret_val; if (bw <= CHANNEL_WIDTH_80) hw_bw_map = bw; else if (bw == CHANNEL_WIDTH_160 || bw == CHANNEL_WIDTH_80_80) hw_bw_map = CHANNEL_WIDTH_160; else hw_bw_map = CHANNEL_WIDTH_20; ret_val = halbb_hw_bw_mode_chk(bb, bw, hw_mode); return hw_bw_map; } u8 halbb_hw_mode_mapping(struct bb_info *bb, u8 wifi_mode) { u8 hw_mode_map = 0; /* Driver wifi mode mapping */ if (wifi_mode & WLAN_MD_11B) /*11B*/ hw_mode_map |= CCK_SUPPORT; if ((wifi_mode & WLAN_MD_11A) || (wifi_mode & WLAN_MD_11G)) /*11G, 11A*/ hw_mode_map |= OFDM_SUPPORT; /* To prevent unnecessary mode from driver, causing confusing ra mask selection after then*/ if (wifi_mode & WLAN_MD_11AX) /*11AX*/ hw_mode_map |= HE_SUPPORT; else if (wifi_mode & WLAN_MD_11AC) /*11AC*/ hw_mode_map |= VHT_SUPPORT_TX; else if (wifi_mode & WLAN_MD_11N) /* 11_N*/ hw_mode_map |= HT_SUPPORT; if (hw_mode_map == 0) BB_WARNING("WRONG Wireless mode !!!!\n"); return hw_mode_map; } bool halbb_ac_n_sgi_chk(struct bb_info *bb, u8 hw_mode, bool en_sgi) { bool sgi_chk = en_sgi; /* Driver wifi mode mapping */ if (hw_mode & HE_SUPPORT) { sgi_chk = false; BB_DBG(bb, DBG_RA, "HE mode sgi is not used!\n"); } return sgi_chk; } u8 halbb_ax_giltf_chk(struct bb_info *bb, u8 hw_mode, u8 giltf_cap) { u8 giltf_chk = giltf_cap; /* Driver wifi mode mapping */ if (!(hw_mode & HE_SUPPORT)) { giltf_chk = 0; BB_DBG(bb, DBG_RA, "In non-HE mode gi_ltf is not used!\n"); } return giltf_chk; } bool halbb_ldpc_chk(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i, u8 hw_mode) { struct protocol_cap_t *asoc_cap_i; bool ldpc_en = false; /* Driver wifi mode mapping */ if (!phl_sta_i) return false; asoc_cap_i = &phl_sta_i->asoc_cap; if (hw_mode & HE_SUPPORT) { ldpc_en |= asoc_cap_i->he_ldpc; BB_DBG(bb, DBG_RA, "Enable HE LDPC\n"); } else if (hw_mode&VHT_SUPPORT_TX) { ldpc_en |= asoc_cap_i->vht_ldpc; BB_DBG(bb, DBG_RA, "Enable VHT LDPC\n"); } else if (hw_mode&HT_SUPPORT) { ldpc_en |= asoc_cap_i->ht_ldpc; BB_DBG(bb, DBG_RA, "Enable HT LDPC\n"); } return ldpc_en; } u8 halbb_nss_mapping(struct bb_info *bb, u8 nss_cap, u8 nss_limit) { u8 mapping_nss = 0; /* Driver tx_nss mapping */ if (nss_cap != 0) mapping_nss = nss_cap - 1; /*nss_limit. e.g. BTC_1ss feature*/ if (nss_limit != 0) { /*nss_limit = 0 means no limit*/ if (mapping_nss > nss_limit - 1) mapping_nss = nss_limit - 1; } /*protection when AP/NIC is connected to a device whose rx_nss > 2*/ if (mapping_nss > (bb->hal_com->rfpath_tx_num - 1)) { mapping_nss = bb->hal_com->rfpath_tx_num - 1; } BB_DBG(bb, DBG_RA, "nss_mapping:{nss_cap,nss_limit,rfpath_tx} = {%d,%d,%d}\n", nss_cap, nss_limit, bb->hal_com->rfpath_tx_num); return mapping_nss; } bool halbb_stbc_mapping(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i, u8 hw_mode) { struct protocol_cap_t *asoc_cap_i; bool stbc_en = false; /* Driver wifi mode mapping */ if (!phl_sta_i) return false; asoc_cap_i = &phl_sta_i->asoc_cap; if (hw_mode & HE_SUPPORT) { if (asoc_cap_i->stbc_he_rx != 0) stbc_en = true; BB_DBG(bb, DBG_RA, "HE STBC %d\n", stbc_en); } else if (hw_mode & VHT_SUPPORT_TX) { if (asoc_cap_i->stbc_vht_rx != 0) stbc_en = true; BB_DBG(bb, DBG_RA, "VHT STBC %d\n", stbc_en); } else if (hw_mode & HT_SUPPORT) { if (asoc_cap_i->stbc_ht_rx != 0) stbc_en = true; BB_DBG(bb, DBG_RA, "HT STBC %d\n", stbc_en); } return stbc_en; } bool halbb_sgi_chk(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i, u8 hw_bw) { struct protocol_cap_t *asoc_cap_i; bool sgi_en = false; /* Driver wifi mode mapping */ if (!phl_sta_i) return false; asoc_cap_i = &phl_sta_i->asoc_cap; if (hw_bw == CHANNEL_WIDTH_20) { sgi_en = asoc_cap_i->sgi_20; BB_DBG(bb, DBG_RA, "Enable 20M SGI\n"); } else if (hw_bw == CHANNEL_WIDTH_40) { sgi_en = asoc_cap_i->sgi_40; BB_DBG(bb, DBG_RA, "Enable 40M SGI\n"); } else if (hw_bw == CHANNEL_WIDTH_80) { sgi_en = asoc_cap_i->sgi_80; BB_DBG(bb, DBG_RA, "Enable 80M SGI\n"); } else if (hw_bw == CHANNEL_WIDTH_160) { sgi_en = asoc_cap_i->sgi_160; BB_DBG(bb, DBG_RA, "Enable 160M SGI\n"); } return sgi_en; } void halbb_ramask_trans(struct bb_info *bb, u8 macid, u64 mask) { struct bb_h2c_ra_cfg_info *ra_cfg = &bb->bb_ra_i[macid].ra_cfg; ra_cfg->ramask[0] = (u8)(mask & 0x00000000000000ff); ra_cfg->ramask[1] = (u8)((mask & 0x000000000000ff00)>>8); ra_cfg->ramask[2] = (u8)((mask & 0x0000000000ff0000)>>16); ra_cfg->ramask[3] = (u8)((mask & 0x00000000ff000000)>>24); ra_cfg->ramask[4] = (u8)((mask & 0x000000ff00000000)>>32); ra_cfg->ramask[5] = (u8)((mask & 0x0000ff0000000000)>>40); ra_cfg->ramask[6] = (u8)((mask & 0x00ff000000000000)>>48); ra_cfg->ramask[7] = (u8)((mask & 0xff00000000000000)>>56); } u8 halbb_get_opt_giltf(struct bb_info *bb, u8 assoc_giltf) { u8 i =0; u8 opt_gi_ltf = 0; if (assoc_giltf & BIT(1)) /* cap. for 4x0.8*/ opt_gi_ltf |= BIT(BB_OPT_GILTF_4XHE08); else if (assoc_giltf & BIT(5)) /* cap. for 1x0.8*/ opt_gi_ltf |= BIT(BB_OPT_GILTF_1XHE08); BB_DBG(bb, DBG_RA, "Ass GILTF=%x,opt GILTF=%x\n", assoc_giltf, opt_gi_ltf); return opt_gi_ltf; } u8 halbb_giltf_trans(struct bb_info *bb, u8 assoc_giltf, u8 cal_giltf) { u8 i =0; BB_DBG(bb, DBG_RA, "Ass GILTF=%x,Cal GILTF=%x\n", assoc_giltf, cal_giltf); if (cal_giltf == RTW_GILTF_LGI_4XHE32 && (assoc_giltf & BIT(0))) return cal_giltf; else if (cal_giltf == RTW_GILTF_SGI_4XHE08 && (assoc_giltf & BIT(1))) return cal_giltf; else if (cal_giltf == RTW_GILTF_2XHE16 && (assoc_giltf & BIT(2))) return cal_giltf; else if (cal_giltf == RTW_GILTF_2XHE08 && (assoc_giltf & BIT(3))) return cal_giltf; else if (cal_giltf == RTW_GILTF_1XHE16 && (assoc_giltf & BIT(4))) return cal_giltf; else if (cal_giltf == RTW_GILTF_1XHE08 && (assoc_giltf & BIT(5))) return cal_giltf; if (assoc_giltf & BIT(3)) return RTW_GILTF_2XHE08; else if (assoc_giltf & BIT(2)) return RTW_GILTF_2XHE16; else if (assoc_giltf & BIT(1)) return RTW_GILTF_SGI_4XHE08; else if (assoc_giltf & BIT(5)) return RTW_GILTF_1XHE08; else if (assoc_giltf & BIT(4)) return RTW_GILTF_1XHE16; else return RTW_GILTF_LGI_4XHE32; } bool rtw_halbb_dft_mask(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { u8 mode = 0; /* connect to phl->assoc*/ u8 hw_md; u64 init_mask = 0; u64 get_mask = 0; u32 mask0, mask1; enum channel_width bw; struct rtw_hal_stainfo_t *hal_sta_i; struct protocol_cap_t *asoc_cap_i; if (!phl_sta_i || !bb) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); return false; } hal_sta_i = phl_sta_i->hal_sta; if (!hal_sta_i) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); return false; } asoc_cap_i = &phl_sta_i->asoc_cap; mode = phl_sta_i->wmode; bw = phl_sta_i->chandef.bw; hw_md = halbb_hw_mode_mapping(bb, mode); BB_DBG(bb, DBG_RA, "Gen Dftmask: mode = %x, hw_md = %x\n", mode, hw_md); if (hw_md & (CCK_SUPPORT | OFDM_SUPPORT)) init_mask = halbb_gen_abg_mask(bb, phl_sta_i); if (init_mask == 0) { if (hw_md & CCK_SUPPORT) { init_mask |= 0x0000000f; BB_DBG(bb, DBG_RA, "[%s]abg mask is null!, set b mask=0xf\n", __func__); } if (hw_md & OFDM_SUPPORT) { init_mask |= 0x00000ff0; BB_DBG(bb, DBG_RA, "[%s]abg mask is null!, set ag mask=0xff\n", __func__); } } if (hw_md & HE_SUPPORT) get_mask = halbb_gen_he_mask(bb, phl_sta_i, bw); else if (hw_md & VHT_SUPPORT_TX) get_mask = halbb_gen_vht_mask(bb, phl_sta_i); else if (hw_md & HT_SUPPORT) get_mask = halbb_gen_ht_mask(bb, phl_sta_i); else get_mask = 0; init_mask |= (get_mask << 12); mask0 = (u32)(init_mask & 0xffffffff); mask1 = (u32)((init_mask >> 32) & 0xffffffff); if (init_mask != 0) { hal_sta_i->ra_info.cur_ra_mask = init_mask; BB_DBG(bb, DBG_RA, "Default mask = %x %x\n", mask0, mask1); return true; } else { BB_WARNING("Error default mask, it should not zero\n"); return false; } } u8 rtw_halbb_arfr_trans(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { struct rtw_hal_stainfo_t *hal_sta_i; u8 mode; u8 arfr_ret = 0x0; if (!phl_sta_i) return false; hal_sta_i = phl_sta_i->hal_sta; if (!hal_sta_i) return false; mode = phl_sta_i->wmode; if (mode & WLAN_MD_11B) /*11B*/ arfr_ret |= CCK_SUPPORT; if ((mode & WLAN_MD_11A)||(mode & WLAN_MD_11G)) /*11G, 11A*/ arfr_ret |= OFDM_SUPPORT; if (mode & WLAN_MD_11N) /* 11_N*/ arfr_ret |= HT_SUPPORT; if (mode & WLAN_MD_11AC) /*11AC*/ arfr_ret |= VHT_SUPPORT_TX; return arfr_ret; /*if (mode|WLAN_MD_11AX ) // 11AX usually can use arfr hw_mode_map |= HE_SUPPORT;*/ } bool rtw_halbb_raregistered(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { /*struct rtw_phl_stainfo_t *phl_sta_i = bb->phl_sta_info[macid];*/ u8 macid; struct bb_h2c_ra_cfg_info *ra_cfg; struct rtw_hal_stainfo_t *hal_sta_i; bool tx_ldpc; bool tx_stbc; bool ret_val = false; u8 tx_nss; u8 rssi; struct protocol_cap_t *asoc_cap_i; u8 rssi_assoc ; u8 mode; bool en_sgi = false; u8 giltf_cap = 0; u8 init_lv; /* Need to mapping with driver wifi mode*/ u32 *bb_h2c; u8 cmdlen = sizeof(struct bb_h2c_ra_cfg_info); u64 mod_mask; BB_DBG(bb, DBG_RA, "====>%s\n", __func__); if (!phl_sta_i || !bb) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); return ret_val; } macid = (u8)(phl_sta_i->macid); ra_cfg = &bb->bb_ra_i[macid].ra_cfg; bb_h2c = (u32 *) ra_cfg; hal_sta_i = phl_sta_i->hal_sta; if (!hal_sta_i) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); return ret_val; } asoc_cap_i = &phl_sta_i->asoc_cap; /*@ use assoc rssi to init ra, only use in ra register, it is an integer using U(8,0)*/ rssi_assoc = (u8)(hal_sta_i->rssi_stat.assoc_rssi); BB_DBG(bb, DBG_RA, "Assoc rssi = %d\n", rssi_assoc); rssi = (u8)(hal_sta_i->rssi_stat.rssi) >> 1; mode = phl_sta_i->wmode; init_lv = halbb_init_ra_by_rssi(bb, rssi_assoc); /*@Becareful RA use our "Tx" capability which means the capability of their "Rx"*/ tx_nss = halbb_nss_mapping(bb, asoc_cap_i->nss_rx, hal_sta_i->ra_info.ra_nss_limit); if (asoc_cap_i->dcm_max_const_rx) ra_cfg->dcm_cap = 1; else ra_cfg->dcm_cap = 0; mode = halbb_hw_mode_mapping(bb, mode); /* ONLY need to get the optional gi-ltf combination for H2C FW*/ /* bit(0)=4x0.8, bit(1)=1x0.8 -> different definition from the drver giltf*/ giltf_cap = halbb_get_opt_giltf(bb, asoc_cap_i->ltf_gi); ra_cfg->giltf_cap = halbb_ax_giltf_chk(bb, mode, giltf_cap); /* giltf assigned by phl/halbb or trained by FW*/ if (hal_sta_i->ra_info.fix_giltf_en == false) { /*giltf from halbb*/ if (bb->ic_type & (BB_RTL8852A | BB_RTL8852B | BB_RTL8852C)) { /*Disable FW train GI_LTF*/ ra_cfg->fix_giltf_en = true; ra_cfg->fix_giltf = RTW_GILTF_2XHE08; /* gi_ltf is decided by delay spread. This is not ready. if (is_giltf_decided_by_delay_sp) ra_cfg->fix_giltf = halbb_ra_giltf_ctrl(bb, macid, delay_sp, asoc_cap_i->ltf_gi); */ } else { /*Enable FW train GI_LTF*/ ra_cfg->fix_giltf_en = false; } } else { /*giltf from phl*/ ra_cfg->fix_giltf = halbb_giltf_trans(bb, asoc_cap_i->ltf_gi, hal_sta_i->ra_info.cal_giltf); } BB_DBG(bb, DBG_RA, "fix_giltf_en(phl)=%d, fix_giltf_en(Final)=%d, fix_giltf=%d\n", hal_sta_i->ra_info.fix_giltf_en, ra_cfg->fix_giltf_en, ra_cfg->fix_giltf); ra_cfg->is_dis_ra = hal_sta_i->ra_info.dis_ra; mod_mask = hal_sta_i->ra_info.cur_ra_mask; ra_cfg->er_cap = asoc_cap_i->er_su; tx_stbc = halbb_stbc_mapping(bb, phl_sta_i, mode); ra_cfg->upd_all= true; ra_cfg->upd_bw_nss_mask= false; ra_cfg->upd_mask= false; if (mode == 0) return ret_val; tx_ldpc = halbb_ldpc_chk(bb, phl_sta_i, mode); ra_cfg->mode_ctrl = mode; ra_cfg->bw_cap = halbb_hw_bw_mapping(bb, phl_sta_i->chandef.bw, mode); en_sgi = halbb_sgi_chk(bb, phl_sta_i, ra_cfg->bw_cap); ra_cfg->macid = macid; ra_cfg->init_rate_lv = init_lv; ra_cfg->en_sgi = halbb_ac_n_sgi_chk(bb, mode, en_sgi); ra_cfg->ldpc_cap = tx_ldpc; ra_cfg->stbc_cap = tx_stbc; ra_cfg->ss_num = tx_nss; /*@ modify ra mask by assoc rssi*/ mod_mask = halbb_ramask_mod(bb, macid, mod_mask, rssi_assoc, mode, tx_nss); halbb_ramask_trans(bb, macid, mod_mask); ret_val = halbb_set_csi_rate(bb, phl_sta_i); if (!ret_val) return ret_val; BB_DBG(bb, DBG_RA, "RA Register=>In: Dis_ra=%x, MD=%x, BW=%x, macid=%x\n", hal_sta_i->ra_info.dis_ra, mode, phl_sta_i->chandef.bw, macid); BB_DBG(bb, DBG_RA, "RA Register=>In: DCM =%x, ER=%x, in_rt=%x, upd_a=%x, sgi=%x, ldpc=%x, stbc=%x\n", ra_cfg->dcm_cap, ra_cfg->er_cap, init_lv, ra_cfg->upd_all, en_sgi, tx_ldpc, tx_stbc); BB_DBG(bb, DBG_RA, "RA Register=>In: SS=%x, GILTF_cap=%x, upd_bnm=%x, upd_m=%x, mask=%llx\n", tx_nss, giltf_cap, ra_cfg->upd_bw_nss_mask, ra_cfg->upd_mask, mod_mask); BB_DBG(bb, DBG_RA, "RA Register=>Out racfg: dis%x bw%x md%x mid%x\n", ra_cfg->is_dis_ra, ra_cfg->bw_cap, ra_cfg->mode_ctrl, ra_cfg->macid); BB_DBG(bb, DBG_RA, "RA Register=>Out h2cp: %x %x %x %x\n", bb_h2c[0], bb_h2c[1], bb_h2c[2], bb_h2c[3]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_MACIDCFG, HALBB_H2C_RA, bb_h2c); return ret_val; } bool rtw_halbb_ra_deregistered(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return true; } bool rtw_halbb_raupdate(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { /* Update only change bw, nss, ramask */ u8 macid; struct bb_h2c_ra_cfg_info *ra_cfg; struct rtw_hal_stainfo_t *hal_sta_i; struct protocol_cap_t *asoc_cap_i; u8 tx_nss; u8 rssi; u8 init_lv = 0; u8 mode = 0; u8 giltf_cap = 0; bool ret_val = false; /* Need to mapping with driver wifi mode*/ u32 *bb_h2c; u8 cmdlen = sizeof(struct bb_h2c_ra_cfg_info); u64 mod_mask; BB_DBG(bb, DBG_RA, "====>%s\n", __func__); if (!phl_sta_i || !bb) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); return ret_val; } macid = (u8) (phl_sta_i->macid); hal_sta_i = phl_sta_i->hal_sta; if (!hal_sta_i) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); return ret_val; } ra_cfg = &bb->bb_ra_i[macid].ra_cfg; mode = ra_cfg->mode_ctrl; bb_h2c = (u32 *) ra_cfg; asoc_cap_i = &phl_sta_i->asoc_cap; rssi = hal_sta_i->rssi_stat.rssi >> 1; /*@Becareful RA use our "Tx" capability which means the capability of their "Rx"*/ tx_nss = halbb_nss_mapping(bb, asoc_cap_i->nss_rx, hal_sta_i->ra_info.ra_nss_limit); ra_cfg->is_dis_ra = hal_sta_i->ra_info.dis_ra; mod_mask = hal_sta_i->ra_info.cur_ra_mask; ra_cfg->upd_all= false; ra_cfg->upd_bw_nss_mask= true; ra_cfg->upd_mask= false; mode = ra_cfg->mode_ctrl; if (mode == 0) return ret_val; ra_cfg->mode_ctrl = mode; /* ONLY need to get the optional gi-ltf combination for H2C FW*/ /* bit(0)=4x0.8, bit(1)=1x0.8 -> different definition from the drver giltf*/ giltf_cap = halbb_get_opt_giltf(bb, asoc_cap_i->ltf_gi); ra_cfg->giltf_cap = halbb_ax_giltf_chk(bb, mode, giltf_cap); /* giltf assigned by phl/halbb or trained by FW*/ if (hal_sta_i->ra_info.fix_giltf_en == false) { /*giltf from halbb*/ if (bb->ic_type & (BB_RTL8852A | BB_RTL8852B | BB_RTL8852C)) { /*Disable FW train GI_LTF*/ ra_cfg->fix_giltf_en = true; ra_cfg->fix_giltf = RTW_GILTF_2XHE08; /* gi_ltf is decided by delay spread. This is not ready. if (is_giltf_decided_by_delay_sp) ra_cfg->fix_giltf = halbb_ra_giltf_ctrl(bb, macid, delay_sp, asoc_cap_i->ltf_gi); */ } else { /*Enable FW train GI_LTF*/ ra_cfg->fix_giltf_en = false; } } else { /*giltf from phl*/ ra_cfg->fix_giltf = halbb_giltf_trans(bb, asoc_cap_i->ltf_gi, hal_sta_i->ra_info.cal_giltf); } BB_DBG(bb, DBG_RA, "fix_giltf_en(phl)=%d, fix_giltf_en(Final)=%d, fix_giltf=%d\n", hal_sta_i->ra_info.fix_giltf_en, ra_cfg->fix_giltf_en, ra_cfg->fix_giltf); ra_cfg->bw_cap = halbb_hw_bw_mapping(bb, phl_sta_i->chandef.bw, mode); ra_cfg->init_rate_lv = 0; ra_cfg->ss_num = tx_nss; mod_mask = halbb_ramask_mod(bb, macid, mod_mask, rssi, mode, tx_nss); halbb_ramask_trans(bb, macid, mod_mask); BB_DBG(bb, DBG_RA, "RA update: %x %x %x\n", bb_h2c[0], bb_h2c[1], bb_h2c[2]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_MACIDCFG, HALBB_H2C_RA, bb_h2c); return ret_val; } bool halbb_ra_update_mask_watchdog(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { u8 macid; struct bb_h2c_ra_cfg_info *ra_cfg; struct rtw_hal_stainfo_t *hal_sta_i; struct protocol_cap_t *asoc_cap_i; u8 tx_nss; u8 rssi; u8 init_lv = 0; u8 mode = 0; u8 giltf_cap = 0; bool ret_val = false; /* Need to mapping with driver wifi mode*/ u32 *bb_h2c; u8 cmdlen = sizeof(struct bb_h2c_ra_cfg_info); u64 mod_mask; macid = (u8)(phl_sta_i->macid); hal_sta_i = phl_sta_i->hal_sta; ra_cfg = &bb->bb_ra_i[macid].ra_cfg; mode = ra_cfg->mode_ctrl; bb_h2c = (u32 *) ra_cfg; asoc_cap_i = &phl_sta_i->asoc_cap; rssi = hal_sta_i->rssi_stat.rssi >> 1; /*@Becareful RA use our "Tx" capability which means the capability of their "Rx"*/ tx_nss = halbb_nss_mapping(bb, asoc_cap_i->nss_rx, hal_sta_i->ra_info.ra_nss_limit); ra_cfg->is_dis_ra = hal_sta_i->ra_info.dis_ra; mod_mask = hal_sta_i->ra_info.cur_ra_mask; ra_cfg->upd_all= false; ra_cfg->upd_bw_nss_mask= false; ra_cfg->upd_mask= true; /* while ra mask is updated, gi_ltf can also be update */ mode = ra_cfg->mode_ctrl; if (mode == 0) return ret_val; ra_cfg->mode_ctrl = mode; ra_cfg->init_rate_lv = 0; /* ONLY need to get the optional gi-ltf combination for H2C FW*/ /* bit(0)=4x0.8, bit(1)=1x0.8 -> different definition from the drver giltf*/ giltf_cap = halbb_get_opt_giltf(bb, asoc_cap_i->ltf_gi); ra_cfg->giltf_cap = halbb_ax_giltf_chk(bb, mode, giltf_cap); /* giltf assigned by phl/halbb or trained by FW*/ if (hal_sta_i->ra_info.fix_giltf_en == false) { /*giltf from halbb*/ if (bb->ic_type & (BB_RTL8852A | BB_RTL8852B | BB_RTL8852C)) { /*Disable FW train GI_LTF*/ ra_cfg->fix_giltf_en = true; ra_cfg->fix_giltf = RTW_GILTF_2XHE08; /* gi_ltf is decided by delay spread. This is not ready. if (is_giltf_decided_by_delay_sp) ra_cfg->fix_giltf = halbb_ra_giltf_ctrl(bb, macid, delay_sp, asoc_cap_i->ltf_gi); */ } else { /*Enable FW train GI_LTF*/ ra_cfg->fix_giltf_en = false; } } else { /*giltf from phl*/ ra_cfg->fix_giltf = halbb_giltf_trans(bb, asoc_cap_i->ltf_gi, hal_sta_i->ra_info.cal_giltf); } BB_DBG(bb, DBG_RA, "fix_giltf_en(phl)=%d, fix_giltf_en(Final)=%d, fix_giltf=%d\n", hal_sta_i->ra_info.fix_giltf_en, ra_cfg->fix_giltf_en, ra_cfg->fix_giltf); mod_mask = halbb_ramask_mod(bb, macid, mod_mask, rssi, mode, tx_nss); halbb_ramask_trans(bb, macid, mod_mask); BB_DBG(bb, DBG_RA, "RA update mask: %x %x %x\n", bb_h2c[0], bb_h2c[1], bb_h2c[2]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_MACIDCFG, HALBB_H2C_RA, bb_h2c); return ret_val; } u32 halbb_get_fw_ra_rpt(struct bb_info *bb, u16 len, u8 *c2h) { u16 macid_rpt; struct rtw_hal_stainfo_t *hal_sta_i; struct rtw_phl_stainfo_t *phl_sta_i; struct rtw_rate_info *rt_i; struct halbb_ra_rpt_info *ra_rpt_i; if (!c2h) return 0; ra_rpt_i = (struct halbb_ra_rpt_info *)c2h; macid_rpt = ra_rpt_i->rpt_macid_l + (ra_rpt_i->rpt_macid_m << 8); if (macid_rpt >= PHL_MAX_STA_NUM) { BB_WARNING("[%s]Error macid = %d!!\n", __func__, macid_rpt); return 0; } if (!bb->sta_exist[macid_rpt]) { BB_WARNING("[%s]Error macid = %d!!\n", __func__, macid_rpt); return 0; } phl_sta_i = bb->phl_sta_info[(u8)macid_rpt]; if (!phl_sta_i) { BB_WARNING("[%s]phl_sta==NULL, Wrong C2H RA macid !!\n", __func__); return 0; } hal_sta_i = phl_sta_i->hal_sta; if (!hal_sta_i) { BB_WARNING("[%s]hal_sta==NULL, Wrong C2H RA macid !!\n", __func__); return 0; } hal_sta_i->ra_info.curr_retry_ratio = ra_rpt_i->retry_ratio; rt_i = &hal_sta_i->ra_info.rpt_rt_i; rt_i->mcs_ss_idx = ra_rpt_i->rpt_mcs_nss; rt_i->gi_ltf = ra_rpt_i->rpt_gi_ltf; rt_i->bw = ra_rpt_i->rpt_bw; rt_i->mode = ra_rpt_i->rpt_md_sel; BB_DBG(bb, DBG_RA, "RA RPT: macid = %d, mode = %d, giltf = %x, mcs_nss = %x\n", macid_rpt, rt_i->mode, rt_i->gi_ltf, rt_i->mcs_ss_idx); return 0; } bool rtw_halbb_query_txsts(struct bb_info *bb, u16 macid0, u16 macid1) { u8 content[4]; u32 *bb_h2c = (u32 *)content; bool ret_val; u16 cmdlen = 4; BB_DBG(bb, DBG_RA, "====> QuerryTxSts : macid = %d %d\n", macid0, macid1); content[0] = (u8)(macid0& 0xff); content[1] = (u8)((macid0>>8)& 0xff); content[2] = (u8)(macid1& 0xff); content[3] = (u8)((macid1>>8)& 0xff); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_GET_TXSTS, HALBB_H2C_RA, bb_h2c); if (!ret_val) BB_WARNING("Error H2C cmd in querry txsts !!\n"); return ret_val; } void halbb_drv_cmac_rpt_parsing(struct bb_info *bb, u8 *rpt) { struct bb_fw_cmac_rpt_info *c_rpt; u16 rpt_len, i; u8 *rpt_tmp = rpt; if (!rpt) return; c_rpt = (struct bb_fw_cmac_rpt_info *)rpt; rpt_len = sizeof(struct bb_fw_cmac_rpt_info); if (rpt_len % 4) { return; } BB_DBG(bb, DBG_RA, "[%d] try_rate=%d, fix_rate=0x%x, final{rate, giltf}={0x%x,0x%x}, data_bw = 0x%x\n", c_rpt->macid, c_rpt->try_rate, c_rpt->fix_rate, c_rpt->final_rate, c_rpt->final_gi_ltf, c_rpt->data_bw); for (i = 0; i < rpt_len; i++) { BB_DBG(bb, DBG_RA, "[%d] 0x%x\n", i, *(u32*)rpt); rpt_tmp += 4; } } u32 halbb_get_txsts_rpt(struct bb_info *bb, u16 len, u8 *c2h) { u16 macid_rpt; u8 i = 0; struct rtw_hal_stainfo_t *hal_sta_i; struct rtw_phl_stainfo_t *phl_sta_i; struct rtw_ra_sta_info *ra_sta_i; struct halbb_txsts_info *txsts_i; u16 tx_total; u16 tx_ok[4]; u16 tx_retry[4]; if (!c2h) return 0; txsts_i = (struct halbb_txsts_info *)c2h; macid_rpt = txsts_i->rpt_macid_l + (txsts_i->rpt_macid_m << 8); if (macid_rpt >= PHL_MAX_STA_NUM) { BB_WARNING("report macid = %d, Error macid !!\n", macid_rpt); return 0; } if (!bb->sta_exist[macid_rpt]) { BB_WARNING("report macid = %d, Error macid !!\n", macid_rpt); return 0; } phl_sta_i = bb->phl_sta_info[(u8)macid_rpt]; if (phl_sta_i == NULL) { BB_WARNING("phl_sta == NULL, Wrong C2H RA macid !!\n"); return 0; } hal_sta_i = phl_sta_i->hal_sta; if (hal_sta_i == NULL) { BB_WARNING("hal_sta == NULL, Wrong C2H RA macid !!\n"); return 0; } ra_sta_i = &hal_sta_i->ra_info; tx_ok[0] = txsts_i->tx_ok_be_l + (txsts_i->tx_ok_be_m << 8); tx_ok[1] = txsts_i->tx_ok_bk_l + (txsts_i->tx_ok_bk_m << 8); tx_ok[2] = txsts_i->tx_ok_vi_l + (txsts_i->tx_ok_vi_m << 8); tx_ok[3] = txsts_i->tx_ok_vo_l + (txsts_i->tx_ok_vo_m << 8); tx_retry[0] = txsts_i->tx_retry_be_l + (txsts_i->tx_retry_be_m << 8); tx_retry[1] = txsts_i->tx_retry_bk_l + (txsts_i->tx_retry_bk_m << 8); tx_retry[2] = txsts_i->tx_retry_vi_l + (txsts_i->tx_retry_vi_m << 8); tx_retry[3] = txsts_i->tx_retry_vo_l + (txsts_i->tx_retry_vo_m << 8); for ( i = 0; i <= 3; i++) { if ((0xffffffff - ra_sta_i->tx_ok_cnt[i]) > (tx_ok[i])) ra_sta_i->tx_ok_cnt[i] += tx_ok[i]; if ((0xffffffff - ra_sta_i->tx_retry_cnt[i]) > (tx_retry[i])) ra_sta_i->tx_retry_cnt[i] += tx_retry[i]; BB_DBG(bb, DBG_RA, "TxOk[%d] = %d, TxRty[%d] = %d\n", i, tx_ok[i], i, tx_retry[i]); } tx_total = txsts_i->tx_total_l + (txsts_i->tx_total_m << 8); if ((0xffffffff - ra_sta_i->tx_total_cnt) > tx_total) ra_sta_i->tx_total_cnt += tx_total; BB_DBG(bb, DBG_RA, "====> GetTxSts : TxTotal = %d\n", tx_total); return 0; } void halbb_ra_rssi_setting_watchdog(struct bb_info *bb) { u8 macid = 0; u8 i = 0, sta_cnt = 0; u16 cmdlen; bool ret_val = true; struct rtw_ra_sta_info *bb_ra; struct rtw_hal_stainfo_t *hal_sta_i; struct bb_h2c_rssi_setting *rssi_i; struct bb_link_info *bb_link = &bb->bb_link_i; u16 rssi_len = 0; u32 *bb_h2c; u8 rssi_a = 0, rssi_b = 0, bcn_rssi_a = 0, bcn_rssi_b = 0; rssi_len = sizeof(struct bb_h2c_rssi_setting) * PHL_MAX_STA_NUM; rssi_i = hal_mem_alloc(bb->hal_com, rssi_len); if (!rssi_i) { BB_WARNING(" Error RSSI allocat failed!!\n"); return; } bb_h2c = (u32 *)rssi_i; cmdlen = rssi_len; for (i = 0; i < PHL_MAX_STA_NUM; i++) { if (!bb->sta_exist[i] || !bb->phl_sta_info[i]) continue; hal_sta_i = bb->phl_sta_info[i]->hal_sta; if (!hal_sta_i) continue; bb_ra = &hal_sta_i->ra_info; if (!(bb_ra->ra_registered)) continue; macid = (u8)(bb->phl_sta_info[i]->macid); BB_DBG(bb, DBG_RA, "Add BB rssi info[%d], macid=%d\n", i, macid); /* Need modify for Nss > 2 */ rssi_a = (hal_sta_i->rssi_stat.rssi_ma_path[0] >> 5) & 0x7f; bcn_rssi_a = (hal_sta_i->rssi_stat.rssi_bcn_ma_path[0] >> 5) & 0x7f; if (!bb->hal_com->dbcc_en) { rssi_b = (hal_sta_i->rssi_stat.rssi_ma_path[1] >> 5) & 0x7f; bcn_rssi_b = (hal_sta_i->rssi_stat.rssi_bcn_ma_path[1] >> 5) & 0x7f; } rssi_i[sta_cnt].macid = macid; rssi_i[sta_cnt].rssi_a = rssi_a | BIT(7); rssi_i[sta_cnt].rssi_b = rssi_b; rssi_i[sta_cnt].bcn_rssi_a = bcn_rssi_a | BIT(7); rssi_i[sta_cnt].bcn_rssi_b = bcn_rssi_b; rssi_i[sta_cnt].drv_ractrl = 0; /* RSVD */ rssi_i[sta_cnt].is_fixed_rate = bb_ra->fixed_rt_en; rssi_i[sta_cnt].fixed_rate = bb_ra->fixed_rt_i.mcs_ss_idx; rssi_i[sta_cnt].fixed_rate_md = bb_ra->fixed_rt_i.mode; rssi_i[sta_cnt].fixed_giltf = bb_ra->fixed_rt_i.gi_ltf; rssi_i[sta_cnt].fixed_bw = bb_ra->fixed_rt_i.bw; sta_cnt++; BB_DBG(bb, DBG_RA, "bcn_rssi{a,b}={%d,%d}, data_rssi{a,b}={%d,%d}\n", bcn_rssi_a, bcn_rssi_b, rssi_a, rssi_b); if (sta_cnt == bb_link->num_linked_client) break; } if (sta_cnt == STA_NUM_RSSI_CMD) { /* Fill endcmd = 1 for last sta */ rssi_i[sta_cnt - 1].endcmd = 1; ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_RSSISETTING, HALBB_H2C_RA, bb_h2c); BB_DBG(bb, DBG_RA, "sta_cnt=%d, RSSI cmd end 1\n", sta_cnt); } else if ((sta_cnt > 0) && (sta_cnt < STA_NUM_RSSI_CMD)) { /* Fill endcmd = 1 for last sta */ rssi_i[sta_cnt - 1].endcmd = 1; rssi_i[sta_cnt].macid = 0xff; ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_RSSISETTING, HALBB_H2C_RA, bb_h2c); BB_DBG(bb, DBG_RA, "sta_cnt=%d, RSSI cmd end 2\n", sta_cnt); } BB_DBG(bb, DBG_RA, "RSSI=>h2c[0~3]: %x %x %x %x\n", bb_h2c[0], bb_h2c[1], bb_h2c[2], bb_h2c[3]); if (ret_val == false) BB_WARNING(" H2C cmd error!!\n"); if (rssi_i) hal_mem_free(bb->hal_com, rssi_i, rssi_len); } void halbb_ra_giltf_ctrl(struct bb_info *bb, u8 macid, u8 delay_sp, u8 assoc_giltf) { struct bb_ra_info *bb_ra = &bb->bb_ra_i[macid]; struct bb_h2c_ra_cfg_info *ra_cfg = &bb->bb_ra_i[macid].ra_cfg; enum rtw_gi_ltf giltf = RTW_GILTF_LGI_4XHE32; if (!bb) return; /*This dhould be decision before ra mask h2c*/ /* GI LTF decision algorithm is needed*/ /*if (delay_sp) giltf = RTW_GILTF_LGI_4XHE32; else giltf = RTW_GILTF_LGI_4XHE32; ra_cfg->giltf = giltf;*/ } void halbb_ra_watchdog(struct bb_info *bb) { struct bb_link_info *bb_link = &bb->bb_link_i; u8 i = 0, sta_cnt = 0, macid = 0; #if 0 if (!(bb->support_ability & BB_RA)) return; #endif halbb_ra_rssi_setting_watchdog(bb); for (i = 0; i < PHL_MAX_STA_NUM; i++) { if (!(bb->sta_exist[i])) continue; if (!(bb->phl_sta_info[i]) || !bb) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); continue; } if (!(bb->phl_sta_info[i]->hal_sta)) { BB_WARNING("Error RA registered !!! Pointer is NULL!!!\n"); continue; } if (!(bb->phl_sta_info[i]->hal_sta->ra_info.ra_registered)) continue; macid = (u8)(bb->phl_sta_info[i]->macid); BB_DBG(bb, DBG_RA, "====>ra update mask[%d], macid=%d\n", i, macid); halbb_ra_update_mask_watchdog(bb, bb->phl_sta_info[i]); sta_cnt++; if (sta_cnt == bb_link->num_linked_client) break; } } void halbb_ra_init(struct bb_info *bb) { struct bb_ra_info *bb_ra = NULL; u8 macid = 0; for (macid = 0; macid < PHL_MAX_STA_NUM; macid ++) { bb_ra = &bb->bb_ra_i[macid]; if (!bb_ra) halbb_mem_set(bb, bb_ra, 0, sizeof (struct bb_ra_info)); } } u8 rtw_halbb_rts_rate(struct bb_info *bb, u16 tx_rate, bool is_erp_prot) { u8 rts_ini_rate = RTW_DATA_RATE_OFDM6; if (is_erp_prot) { /* use CCK rate as RTS */ rts_ini_rate = RTW_DATA_RATE_CCK1; } else { switch (tx_rate) { case RTW_DATA_RATE_VHT_NSS4_MCS9: case RTW_DATA_RATE_VHT_NSS4_MCS8: case RTW_DATA_RATE_VHT_NSS4_MCS7: case RTW_DATA_RATE_VHT_NSS4_MCS6: case RTW_DATA_RATE_VHT_NSS4_MCS5: case RTW_DATA_RATE_VHT_NSS4_MCS4: case RTW_DATA_RATE_VHT_NSS4_MCS3: case RTW_DATA_RATE_VHT_NSS3_MCS9: case RTW_DATA_RATE_VHT_NSS3_MCS8: case RTW_DATA_RATE_VHT_NSS3_MCS7: case RTW_DATA_RATE_VHT_NSS3_MCS6: case RTW_DATA_RATE_VHT_NSS3_MCS5: case RTW_DATA_RATE_VHT_NSS3_MCS4: case RTW_DATA_RATE_VHT_NSS3_MCS3: case RTW_DATA_RATE_VHT_NSS2_MCS9: case RTW_DATA_RATE_VHT_NSS2_MCS8: case RTW_DATA_RATE_VHT_NSS2_MCS7: case RTW_DATA_RATE_VHT_NSS2_MCS6: case RTW_DATA_RATE_VHT_NSS2_MCS5: case RTW_DATA_RATE_VHT_NSS2_MCS4: case RTW_DATA_RATE_VHT_NSS2_MCS3: case RTW_DATA_RATE_VHT_NSS1_MCS9: case RTW_DATA_RATE_VHT_NSS1_MCS8: case RTW_DATA_RATE_VHT_NSS1_MCS7: case RTW_DATA_RATE_VHT_NSS1_MCS6: case RTW_DATA_RATE_VHT_NSS1_MCS5: case RTW_DATA_RATE_VHT_NSS1_MCS4: case RTW_DATA_RATE_VHT_NSS1_MCS3: case RTW_DATA_RATE_MCS31: case RTW_DATA_RATE_MCS30: case RTW_DATA_RATE_MCS29: case RTW_DATA_RATE_MCS28: case RTW_DATA_RATE_MCS27: case RTW_DATA_RATE_MCS23: case RTW_DATA_RATE_MCS22: case RTW_DATA_RATE_MCS21: case RTW_DATA_RATE_MCS20: case RTW_DATA_RATE_MCS19: case RTW_DATA_RATE_MCS15: case RTW_DATA_RATE_MCS14: case RTW_DATA_RATE_MCS13: case RTW_DATA_RATE_MCS12: case RTW_DATA_RATE_MCS11: case RTW_DATA_RATE_MCS7: case RTW_DATA_RATE_MCS6: case RTW_DATA_RATE_MCS5: case RTW_DATA_RATE_MCS4: case RTW_DATA_RATE_MCS3: case RTW_DATA_RATE_OFDM54: case RTW_DATA_RATE_OFDM48: case RTW_DATA_RATE_OFDM36: case RTW_DATA_RATE_OFDM24: rts_ini_rate = RTW_DATA_RATE_OFDM24; break; case RTW_DATA_RATE_VHT_NSS4_MCS2: case RTW_DATA_RATE_VHT_NSS4_MCS1: case RTW_DATA_RATE_VHT_NSS3_MCS2: case RTW_DATA_RATE_VHT_NSS3_MCS1: case RTW_DATA_RATE_VHT_NSS2_MCS2: case RTW_DATA_RATE_VHT_NSS2_MCS1: case RTW_DATA_RATE_VHT_NSS1_MCS2: case RTW_DATA_RATE_VHT_NSS1_MCS1: case RTW_DATA_RATE_MCS26: case RTW_DATA_RATE_MCS25: case RTW_DATA_RATE_MCS18: case RTW_DATA_RATE_MCS17: case RTW_DATA_RATE_MCS10: case RTW_DATA_RATE_MCS9: case RTW_DATA_RATE_MCS2: case RTW_DATA_RATE_MCS1: case RTW_DATA_RATE_OFDM18: case RTW_DATA_RATE_OFDM12: rts_ini_rate = RTW_DATA_RATE_OFDM12; break; case RTW_DATA_RATE_VHT_NSS4_MCS0: case RTW_DATA_RATE_VHT_NSS3_MCS0: case RTW_DATA_RATE_VHT_NSS2_MCS0: case RTW_DATA_RATE_VHT_NSS1_MCS0: case RTW_DATA_RATE_MCS24: case RTW_DATA_RATE_MCS16: case RTW_DATA_RATE_MCS8: case RTW_DATA_RATE_MCS0: case RTW_DATA_RATE_OFDM9: case RTW_DATA_RATE_OFDM6: rts_ini_rate = RTW_DATA_RATE_OFDM6; break; case RTW_DATA_RATE_CCK11: case RTW_DATA_RATE_CCK5_5: case RTW_DATA_RATE_CCK2: case RTW_DATA_RATE_CCK1: rts_ini_rate = RTW_DATA_RATE_CCK1; break; default: rts_ini_rate = RTW_DATA_RATE_OFDM6; break; } } if (bb->hal_com->band[0].cur_chandef.band == BAND_ON_5G) { if (rts_ini_rate < RTW_DATA_RATE_OFDM6) rts_ini_rate = RTW_DATA_RATE_OFDM6; } return rts_ini_rate; } void halbb_ra_dbg(struct bb_info *bb, char input[][16], u32 *_used, char *output, u32 *_out_len) { char help[] = "-h"; u32 val[10] = {0}; u32 used = *_used; u32 out_len = *_out_len; u32 tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0; u8 i; bool ret_val = false; struct rtw_ra_sta_info *bb_ra; struct rtw_hal_stainfo_t *hal_sta_i; //struct bb_h2c_rssi_setting *rssi_i; u16 rssi_len = 0; u8 rssi_a = 0, rssi_b = 0, bcn_rssi_a = 0, bcn_rssi_b = 0; if (_os_strcmp(input[1], help) == 0) { //BB_DBG_CNSL(out_len, used, output + used, out_len - used, // "{Test ra mode}: [ra] [100] [macid] [mode 0: fixed rate, 1:fixed macidcfg]\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{Fix rate} [ra] [1] [macid] [mode] [giltf] [ss_mcs] [bw])\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{Auto rate}: [ra] [2] [macid]\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "=============Notes=============>\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "[mode]: 0:(legacy), 1:(HT), 2:(VHT), 3:(HE)\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "[giltf]: 0: (4xHE-LTF 3.2usGI), 1: (4xHE-LTF 0.8usGI), 2: (2xHE-LTF 1.6usGI)\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "[giltf]: 3: (2xHE-LTF 0.8usGI), 4: (1xHE-LTF 1.6usGI), 5: (1xHE-LTF 0.8usGI)\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "[ss_mcs]: (Bitmap format) [6:4]: Nsts [3:0]: MCS\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "==============================>\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{Drvier shift rate up/down threshold}: [ra] [3] [macid] [0: Increase th. (Tend to RU) 1: Decrease th (Tend to RD)] [percent]\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{Manually adjust RA mask}: [ra] [4] [macid] [0: dis. manual adj. RA mask; 1: en. manual adj. RA mask] [0: mask; 1: reveal] [rate_mode] [ss_mcs]\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{d_o_timer}: [ra] [5] [macid] [en] [timer (FW default 20)]\n"); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{debug bb reg}: [ra] [dbgreg]\n"); //BB_DBG_CNSL(out_len, used, output + used, out_len - used, // "{Fix rate & ra mask}: ra (3 [macid] [mode] [giltf] [ss_mcs] [mask1] [mask0])}\n"); goto out; } for (i = 0; i < 8; i++) { if (input[i + 1]) HALBB_SCAN(input[i + 1], DCMD_DECIMAL, &val[i]); } //rssi_len = sizeof(struct bb_h2c_rssi_setting); //rssi_i = hal_mem_alloc(bb->hal_com, rssi_len); if (0) { /* Test RA mode */ /* bb_h2c = (u32 *) &ra_cfg; ra_cfg.bw_cap = 0; ra_cfg.mode_ctrl = (u8)val[2]; ra_cfg.is_dis_ra= false; ra_cfg.macid = (u8)val[1]; ra_cfg.stbc_cap = false; ra_cfg.ldpc_cap = false; ra_cfg.en_sgi = false; ra_cfg.upd_all = true; ra_cfg.init_rate_lv = 1; ra_cfg.er_cap = false; ra_cfg.dcm_cap = false; ra_cfg.upd_mask = false; ra_cfg.upd_bw_nss_mask = false; ra_cfg.giltf = 0; ra_cfg.ss_num = 1; for (i = 0; i < 8; i++) ra_cfg.ramask[i] = 0xff; BB_DBG(bb, DBG_RA, "RA Register: %x %x %x\n", bb_h2c[0], bb_h2c[1], bb_h2c[2]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_MACIDCFG, HALBB_H2C_RA, bb_h2c); */ } else if (val[0] == 1) { struct bb_h2c_rssi_setting rssi_i; u32 *bb_h2c = (u32 *) &rssi_i; u8 cmdlen = sizeof(struct bb_h2c_rssi_setting); hal_sta_i = bb->phl_sta_info[(u8)val[1]]->hal_sta; bb_ra = &hal_sta_i->ra_info; if (bb_ra->ra_registered) { BB_DBG(bb, DBG_RA, "RA fix rate macid=[%d]\n", (u8)val[1]); /* Need modify for Nss > 2 */ rssi_a = (hal_sta_i->rssi_stat.rssi_ma_path[0] >> 5) & 0x7f; bcn_rssi_a = (hal_sta_i->rssi_stat.rssi_bcn_ma_path[0] >> 5) & 0x7f; if (!bb->hal_com->dbcc_en) { rssi_b = (hal_sta_i->rssi_stat.rssi_ma_path[1] >> 5) & 0x7f; bcn_rssi_b = (hal_sta_i->rssi_stat.rssi_bcn_ma_path[1] >> 5) & 0x7f; } rssi_i.macid = (u8)val[1]; rssi_i.rssi_a = rssi_a | BIT(7); rssi_i.rssi_b = rssi_b; rssi_i.bcn_rssi_a = bcn_rssi_a | BIT(7); rssi_i.bcn_rssi_b = bcn_rssi_b; rssi_i.is_fixed_rate = true; rssi_i.fixed_rate = (u8)val[4]; rssi_i.fixed_giltf = (u8)val[3]; rssi_i.fixed_bw = (u8)val[5]; rssi_i.fixed_rate_md = (u8)val[2]; rssi_i.endcmd = 1; bb_ra->fixed_rt_en = rssi_i.is_fixed_rate; bb_ra->fixed_rt_i.mcs_ss_idx = rssi_i.fixed_rate; bb_ra->fixed_rt_i.mode = rssi_i.fixed_rate_md; bb_ra->fixed_rt_i.gi_ltf = rssi_i.fixed_giltf; bb_ra->fixed_rt_i.bw = rssi_i.fixed_bw; BB_DBG(bb, DBG_RA, "RA fix rate H2C: %x %x\n", bb_h2c[0], bb_h2c[1]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_RSSISETTING, HALBB_H2C_RA, bb_h2c); } else { BB_DBG(bb, DBG_RA, "No Link ! RA rssi cmd fail!\n"); } } else if (val[0] == 2) { struct bb_h2c_rssi_setting rssi_i; u32 *bb_h2c = (u32 *) &rssi_i; u8 cmdlen = sizeof(struct bb_h2c_rssi_setting); hal_sta_i = bb->phl_sta_info[(u8)val[1]]->hal_sta; bb_ra = &hal_sta_i->ra_info; if (bb_ra->ra_registered) { BB_DBG(bb, DBG_RA, "RA auto rate macid=[%d]\n", (u8)val[1]); /* Need modify for Nss > 2 */ rssi_a = (hal_sta_i->rssi_stat.rssi_ma_path[0] >> 5) & 0x7f; bcn_rssi_a = (hal_sta_i->rssi_stat.rssi_bcn_ma_path[0] >> 5) & 0x7f; if (!bb->hal_com->dbcc_en) { rssi_b = (hal_sta_i->rssi_stat.rssi_ma_path[1] >> 5) & 0x7f; bcn_rssi_b = (hal_sta_i->rssi_stat.rssi_bcn_ma_path[1] >> 5) & 0x7f; } rssi_i.macid = (u8)val[1]; rssi_i.rssi_a = rssi_a | BIT(7); rssi_i.rssi_b = rssi_b; rssi_i.bcn_rssi_a = bcn_rssi_a | BIT(7); rssi_i.bcn_rssi_b = bcn_rssi_b; rssi_i.is_fixed_rate = false; rssi_i.endcmd = 1; bb_ra->fixed_rt_en = rssi_i.is_fixed_rate; BB_DBG(bb, DBG_RA, "RA auto rate H2C: %x %x\n", bb_h2c[0], bb_h2c[1]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_RSSISETTING, HALBB_H2C_RA, bb_h2c); } else { BB_DBG(bb, DBG_RA, "No Link ! RA rssi cmd fail!\n"); } } else if (val[0] == 3) { struct bb_h2c_ra_adjust ra_th_i; u32 *bb_h2c = (u32 *) &ra_th_i; u8 cmdlen = sizeof(struct bb_h2c_ra_adjust); hal_sta_i = bb->phl_sta_info[(u8)val[1]]->hal_sta; bb_ra = &hal_sta_i->ra_info; if (bb_ra->ra_registered) { BB_DBG(bb, DBG_RA, "RA adjust th. macid=[%d]\n", (u8)val[1]); ra_th_i.macid = (u8)val[1]; ra_th_i.drv_shift_en = (u8)val[2] & 0x01; ra_th_i.drv_shift_value= (u8)val[3] & 0x7f; BB_DBG(bb, DBG_RA, "RA adjust %s th =[%d]\n", ra_th_i.drv_shift_en == 0x1 ? "RD": "RU", ra_th_i.drv_shift_value); BB_DBG(bb, DBG_RA, "RA adjust th H2C: %x %x\n", bb_h2c[0], bb_h2c[1]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_RA_ADJUST, HALBB_H2C_RA, bb_h2c); } else { BB_DBG(bb, DBG_RA, "No Link ! RA rssi cmd fail!\n"); } } else if (val[0] == 4) { struct bb_h2c_ra_mask ra_mask_i; u32 *bb_h2c = (u32 *) &ra_mask_i; u8 cmdlen = sizeof(struct bb_h2c_ra_mask); hal_sta_i = bb->phl_sta_info[(u8)val[1]]->hal_sta; bb_ra = &hal_sta_i->ra_info; if (bb_ra->ra_registered) { BB_DBG(bb, DBG_RA, "macid=[%d]\n", (u8)val[1]); ra_mask_i.macid = (u8)val[1]; ra_mask_i.is_manual_adjust_ra_mask = (u8)val[2] & 0x01; ra_mask_i.mask_or_reveal = (u8)val[3] & 0x01; ra_mask_i.mask_rate_md= (u8)val[4]; ra_mask_i.mask_rate= (u8)val[5]; BB_DBG(bb, DBG_RA, "Manual adjust RA mask = %d\n", ra_mask_i.is_manual_adjust_ra_mask); BB_DBG(bb, DBG_RA, "Adjust mode=%d, rate(d')=%d\n", ra_mask_i.mask_rate_md, ra_mask_i.mask_rate); BB_DBG(bb, DBG_RA, "[%s] this rate in RA mask\n", ra_mask_i.mask_or_reveal ? "Reveal": "Mask"); BB_DBG(bb, DBG_RA, "RA adjust th H2C: %x %x\n", bb_h2c[0], bb_h2c[1]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_ADJUST_RA_MASK, HALBB_H2C_RA, bb_h2c); } else { BB_DBG(bb, DBG_RA, "No Link ! RA rssi cmd fail!\n"); } } else if (val[0] == 5) { struct bb_h2c_ra_d_o_timer ra_d_o_timer_i; u32 *bb_h2c = (u32 *) &ra_d_o_timer_i; u8 cmdlen = sizeof(struct bb_h2c_ra_d_o_timer); hal_sta_i = bb->phl_sta_info[(u8)val[1]]->hal_sta; bb_ra = &hal_sta_i->ra_info; if (bb_ra->ra_registered) { BB_DBG(bb, DBG_RA, "RA d_o_timer macid=[%d]\n", (u8)val[1]); ra_d_o_timer_i.macid = (u8)val[1]; ra_d_o_timer_i.d_o_timer_en = (u8)val[2] & 0x01; ra_d_o_timer_i.d_o_timer_value= (u8)val[3] & 0x7f; BB_DBG(bb, DBG_RA, "RA d_o_timer {en,value} = {%d,%d}\n", ra_d_o_timer_i.d_o_timer_en , ra_d_o_timer_i.d_o_timer_value); BB_DBG(bb, DBG_RA, "RA d_o_timer H2C: %x\n", bb_h2c[0]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, RA_H2C_RA_D_O_TIMER, HALBB_H2C_RA, bb_h2c); } else { BB_DBG(bb, DBG_RA, "No Link ! RA d_o_timer cmd fail!\n"); } } else if (_os_strcmp(input[1], "dbgreg") == 0) { tmp1 = halbb_get_reg(bb, 0x160, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x164, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "CMAC_table DWORD0{macid0,macid1}={0x%x,0x%x}\n", tmp1, tmp2); tmp1 = halbb_get_reg(bb, 0x184, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x188, MASKDWORD); tmp3 = halbb_get_reg(bb, 0x18c, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{PER,RDR,R4}={%d,%d,%d}\n", tmp1, tmp2, tmp3); tmp1 = halbb_get_reg(bb, 0x168, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x16c, MASKDWORD); tmp3 = halbb_get_reg(bb, 0x170, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "{rate_up_lmt_cnt,PER_ma,VAR}={%d,%d,%d}\n", tmp1, tmp2, tmp3); tmp1 = halbb_get_reg(bb, 0x17c, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x180, MASKDWORD); tmp3 = halbb_get_reg(bb, 0x174, MASKDWORD); tmp4 = halbb_get_reg(bb, 0x178, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "decision_offset:{n,p}={%d,%d},TH:{RD,RU}={%d,%d}\n", tmp1, tmp2, tmp3, tmp4); tmp1 = halbb_get_reg(bb, 0x1b0, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x1b4, MASKDWORD); tmp3 = halbb_get_reg(bb, 0x1b8, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "try:{PER,RDR,R4}={%d,%d,%d}\n", tmp1, tmp2, tmp3); tmp1 = halbb_get_reg(bb, 0x1bc, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x19c, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "TxRPT.total_tmp=%d,RA_timer=%d\n", tmp1, tmp2); tmp1 = halbb_get_reg(bb, 0x190, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x194, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "rate decision early return:{total=0/disra/trying, R4}={%d,%d}\n", tmp1, tmp2); tmp1 = halbb_get_reg(bb, 0x1c4, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x1c0, MASKDWORD); tmp3 = halbb_get_reg(bb, 0x1c8, MASKDWORD); tmp4 = halbb_get_reg(bb, 0x1cc, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "RA mask[H->L]={0x%x,0x%x}, highest_rate=0x%x, lowest_rate=0x%x\n", tmp1, tmp2, tmp3, tmp4); tmp1 = halbb_get_reg(bb, 0x1d0, MASKDWORD); tmp2 = halbb_get_reg(bb, 0x1d4, MASKDWORD); tmp3 = halbb_get_reg(bb, 0x1d8, MASKDWORD); tmp4 = halbb_get_reg(bb, 0x1dc, MASKDWORD); BB_DBG_CNSL(out_len, used, output + used, out_len - used, "RA registered, H2C Byte[0->3]={0x%x,0x%x,0x%x,0x%x}\n", tmp1, tmp2, tmp3, tmp4); } //if (rssi_i) // hal_mem_free(bb->hal_com, rssi_i, rssi_len); out: *_used = used; *_out_len = out_len; } #endif