Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtw88: Enable 802.11ac beamformee support

Enable MU-MIMO transmit beamformee support for chipset 8822b and 8822c.

If the driver is in station mode and associated with an AP, and the
capabilities of both meet the requirement of beamforming, driver will
run as a beamformee and the corresponding chip settings will be set.

In addition, module parameter support_bf is added to enable or disable
beamforming. Sometimes driver will need to disable for inter-operate
issues, and it would be easier for driver to debug.

Signed-off-by: Tzu-En Huang <tehuang@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>

authored by

Tzu-En Huang and committed by
Kalle Valo
0bd95573 c97ee3e0

+692
+1
drivers/net/wireless/realtek/rtw88/Makefile
··· 14 14 fw.o \ 15 15 ps.o \ 16 16 sec.o \ 17 + bf.o \ 17 18 regd.o 18 19 19 20 rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o
+400
drivers/net/wireless/realtek/rtw88/bf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 + /* Copyright(c) 2018-2019 Realtek Corporation. 3 + */ 4 + 5 + #include "main.h" 6 + #include "reg.h" 7 + #include "bf.h" 8 + #include "debug.h" 9 + 10 + void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 11 + struct ieee80211_bss_conf *bss_conf) 12 + { 13 + struct rtw_chip_info *chip = rtwdev->chip; 14 + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 15 + struct rtw_bfee *bfee = &rtwvif->bfee; 16 + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; 17 + 18 + if (bfee->role == RTW_BFEE_NONE) 19 + return; 20 + 21 + if (bfee->role == RTW_BFEE_MU) 22 + bfinfo->bfer_mu_cnt--; 23 + else if (bfee->role == RTW_BFEE_SU) 24 + bfinfo->bfer_su_cnt--; 25 + 26 + chip->ops->config_bfee(rtwdev, rtwvif, bfee, false); 27 + 28 + bfee->role = RTW_BFEE_NONE; 29 + } 30 + 31 + void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 32 + struct ieee80211_bss_conf *bss_conf) 33 + { 34 + struct ieee80211_hw *hw = rtwdev->hw; 35 + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 36 + struct rtw_bfee *bfee = &rtwvif->bfee; 37 + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; 38 + struct rtw_chip_info *chip = rtwdev->chip; 39 + struct ieee80211_sta *sta; 40 + struct ieee80211_sta_vht_cap *vht_cap; 41 + struct ieee80211_sta_vht_cap *ic_vht_cap; 42 + const u8 *bssid = bss_conf->bssid; 43 + u32 sound_dim; 44 + u8 bfee_role = RTW_BFEE_NONE; 45 + u8 i; 46 + 47 + if (!(chip->band & RTW_BAND_5G)) 48 + return; 49 + 50 + rcu_read_lock(); 51 + 52 + sta = ieee80211_find_sta(vif, bssid); 53 + if (!sta) { 54 + rtw_warn(rtwdev, "failed to find station entry for bss %pM\n", 55 + bssid); 56 + goto out_unlock; 57 + } 58 + 59 + ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; 60 + vht_cap = &sta->vht_cap; 61 + 62 + if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && 63 + (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { 64 + if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) { 65 + rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n"); 66 + goto out_unlock; 67 + } 68 + 69 + ether_addr_copy(bfee->mac_addr, bssid); 70 + bfee_role = RTW_BFEE_MU; 71 + bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); 72 + bfee->aid = bss_conf->aid; 73 + bfinfo->bfer_mu_cnt++; 74 + 75 + chip->ops->config_bfee(rtwdev, rtwvif, bfee, true); 76 + } else if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) && 77 + (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { 78 + if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) { 79 + rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n"); 80 + goto out_unlock; 81 + } 82 + 83 + sound_dim = vht_cap->cap & 84 + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; 85 + sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; 86 + 87 + ether_addr_copy(bfee->mac_addr, bssid); 88 + bfee_role = RTW_BFEE_SU; 89 + bfee->sound_dim = (u8)sound_dim; 90 + bfee->g_id = 0; 91 + bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); 92 + bfinfo->bfer_su_cnt++; 93 + for (i = 0; i < chip->bfer_su_max_num; i++) { 94 + if (!test_bit(i, bfinfo->bfer_su_reg_maping)) { 95 + set_bit(i, bfinfo->bfer_su_reg_maping); 96 + bfee->su_reg_index = i; 97 + break; 98 + } 99 + } 100 + 101 + chip->ops->config_bfee(rtwdev, rtwvif, bfee, true); 102 + } 103 + 104 + out_unlock: 105 + bfee->role = bfee_role; 106 + rcu_read_unlock(); 107 + } 108 + 109 + void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, 110 + struct mu_bfer_init_para *param) 111 + { 112 + u16 mu_bf_ctl = 0; 113 + u8 *addr = param->bfer_address; 114 + int i; 115 + 116 + for (i = 0; i < ETH_ALEN; i++) 117 + rtw_write8(rtwdev, REG_ASSOCIATED_BFMER0_INFO + i, addr[i]); 118 + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 6, param->paid); 119 + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, param->csi_para); 120 + 121 + mu_bf_ctl = rtw_read16(rtwdev, REG_WMAC_MU_BF_CTL) & 0xC000; 122 + mu_bf_ctl |= param->my_aid | (param->csi_length_sel << 12); 123 + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, mu_bf_ctl); 124 + } 125 + 126 + void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif, 127 + enum rtw_trx_desc_rate rate) 128 + { 129 + u32 psf_ctl = 0; 130 + u8 csi_rsc = 0x1; 131 + 132 + psf_ctl = rtw_read32(rtwdev, REG_BBPSF_CTRL) | 133 + BIT_WMAC_USE_NDPARATE | 134 + (csi_rsc << 13); 135 + 136 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING); 137 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, 0x26); 138 + rtw_write8_clr(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF_REPORT_POLL); 139 + rtw_write8_clr(rtwdev, REG_RXFLTMAP4, BIT_RXFLTMAP4_BF_REPORT_POLL); 140 + 141 + if (vif->net_type == RTW_NET_AP_MODE) 142 + rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl | BIT(12)); 143 + else 144 + rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl & ~BIT(12)); 145 + } 146 + 147 + void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param) 148 + { 149 + u8 mu_tbl_sel; 150 + u8 mu_valid; 151 + 152 + mu_valid = rtw_read8(rtwdev, REG_MU_TX_CTL) & 153 + ~BIT_MASK_R_MU_TABLE_VALID; 154 + 155 + rtw_write8(rtwdev, REG_MU_TX_CTL, 156 + (mu_valid | BIT(0) | BIT(1)) & ~(BIT(7))); 157 + 158 + mu_tbl_sel = rtw_read8(rtwdev, REG_MU_TX_CTL + 1) & 0xF8; 159 + 160 + rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel); 161 + rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[0]); 162 + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[0]); 163 + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4, 164 + param->given_user_pos[1]); 165 + 166 + rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel | 1); 167 + rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[1]); 168 + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[2]); 169 + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4, 170 + param->given_user_pos[3]); 171 + } 172 + 173 + void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev) 174 + { 175 + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0); 176 + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0); 177 + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0); 178 + rtw_write8(rtwdev, REG_MU_TX_CTL, 0); 179 + } 180 + 181 + void rtw_bf_del_sounding(struct rtw_dev *rtwdev) 182 + { 183 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, 0); 184 + } 185 + 186 + void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, 187 + struct rtw_bfee *bfee) 188 + { 189 + u8 nc_index = 1; 190 + u8 nr_index = bfee->sound_dim; 191 + u8 grouping = 0, codebookinfo = 1, coefficientsize = 3; 192 + u32 addr_bfer_info, addr_csi_rpt, csi_param; 193 + u8 i; 194 + 195 + rtw_dbg(rtwdev, RTW_DBG_BF, "config as an su bfee\n"); 196 + 197 + switch (bfee->su_reg_index) { 198 + case 1: 199 + addr_bfer_info = REG_ASSOCIATED_BFMER1_INFO; 200 + addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20 + 2; 201 + break; 202 + case 0: 203 + default: 204 + addr_bfer_info = REG_ASSOCIATED_BFMER0_INFO; 205 + addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20; 206 + break; 207 + } 208 + 209 + /* Sounding protocol control */ 210 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING); 211 + 212 + /* MAC address/Partial AID of Beamformer */ 213 + for (i = 0; i < ETH_ALEN; i++) 214 + rtw_write8(rtwdev, addr_bfer_info + i, bfee->mac_addr[i]); 215 + 216 + csi_param = (u16)((coefficientsize << 10) | 217 + (codebookinfo << 8) | 218 + (grouping << 6) | 219 + (nr_index << 3) | 220 + nc_index); 221 + rtw_write16(rtwdev, addr_csi_rpt, csi_param); 222 + 223 + /* ndp rx standby timer */ 224 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, RTW_NDP_RX_STANDBY_TIME); 225 + } 226 + 227 + /* nc index: 1 2T2R 0 1T1R 228 + * nr index: 1 use Nsts 0 use reg setting 229 + * codebookinfo: 1 802.11ac 3 802.11n 230 + */ 231 + void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, 232 + struct rtw_bfee *bfee) 233 + { 234 + struct rtw_bf_info *bf_info = &rtwdev->bf_info; 235 + struct mu_bfer_init_para param; 236 + u8 nc_index = 1, nr_index = 1; 237 + u8 grouping = 0, codebookinfo = 1, coefficientsize = 0; 238 + u32 csi_param; 239 + 240 + rtw_dbg(rtwdev, RTW_DBG_BF, "config as an mu bfee\n"); 241 + 242 + csi_param = (u16)((coefficientsize << 10) | 243 + (codebookinfo << 8) | 244 + (grouping << 6) | 245 + (nr_index << 3) | 246 + nc_index); 247 + 248 + rtw_dbg(rtwdev, RTW_DBG_BF, "nc=%d nr=%d group=%d codebookinfo=%d coefficientsize=%d\n", 249 + nc_index, nr_index, grouping, codebookinfo, 250 + coefficientsize); 251 + 252 + param.paid = bfee->p_aid; 253 + param.csi_para = csi_param; 254 + param.my_aid = bfee->aid & 0xfff; 255 + param.csi_length_sel = HAL_CSI_SEG_4K; 256 + ether_addr_copy(param.bfer_address, bfee->mac_addr); 257 + 258 + rtw_bf_init_bfer_entry_mu(rtwdev, &param); 259 + 260 + bf_info->cur_csi_rpt_rate = DESC_RATE6M; 261 + rtw_bf_cfg_sounding(rtwdev, vif, DESC_RATE6M); 262 + 263 + /* accept action_no_ack */ 264 + rtw_write16_set(rtwdev, REG_RXFLTMAP0, BIT_RXFLTMAP0_ACTIONNOACK); 265 + 266 + /* accept NDPA and BF report poll */ 267 + rtw_write16_set(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF); 268 + } 269 + 270 + void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, 271 + struct rtw_bfee *bfee) 272 + { 273 + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; 274 + 275 + rtw_dbg(rtwdev, RTW_DBG_BF, "remove as a su bfee\n"); 276 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_REMOVE); 277 + 278 + switch (bfee->su_reg_index) { 279 + case 0: 280 + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0); 281 + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0); 282 + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, 0); 283 + break; 284 + case 1: 285 + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER1_INFO, 0); 286 + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER1_INFO + 4, 0); 287 + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20 + 2, 0); 288 + break; 289 + } 290 + 291 + clear_bit(bfee->su_reg_index, bfinfo->bfer_su_reg_maping); 292 + bfee->su_reg_index = 0xFF; 293 + } 294 + 295 + void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, 296 + struct rtw_bfee *bfee) 297 + { 298 + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; 299 + 300 + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_REMOVE); 301 + 302 + rtw_bf_del_bfer_entry_mu(rtwdev); 303 + 304 + if (bfinfo->bfer_su_cnt == 0 && bfinfo->bfer_mu_cnt == 0) 305 + rtw_bf_del_sounding(rtwdev); 306 + } 307 + 308 + void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 309 + struct ieee80211_bss_conf *conf) 310 + { 311 + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 312 + struct rtw_bfee *bfee = &rtwvif->bfee; 313 + struct cfg_mumimo_para param; 314 + 315 + if (bfee->role != RTW_BFEE_MU) { 316 + rtw_dbg(rtwdev, RTW_DBG_BF, "this vif is not mu bfee\n"); 317 + return; 318 + } 319 + 320 + param.grouping_bitmap = 0; 321 + param.mu_tx_en = 0; 322 + memset(param.sounding_sts, 0, 6); 323 + memcpy(param.given_gid_tab, conf->mu_group.membership, 8); 324 + memcpy(param.given_user_pos, conf->mu_group.position, 16); 325 + rtw_dbg(rtwdev, RTW_DBG_BF, "STA0: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n", 326 + param.given_gid_tab[0], param.given_user_pos[0], 327 + param.given_user_pos[1]); 328 + 329 + rtw_dbg(rtwdev, RTW_DBG_BF, "STA1: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n", 330 + param.given_gid_tab[1], param.given_user_pos[2], 331 + param.given_user_pos[3]); 332 + 333 + rtw_bf_cfg_mu_bfee(rtwdev, &param); 334 + } 335 + 336 + void rtw_bf_phy_init(struct rtw_dev *rtwdev) 337 + { 338 + u8 tmp8; 339 + u32 tmp32; 340 + u8 retry_limit = 0xA; 341 + u8 ndpa_rate = 0x10; 342 + u8 ack_policy = 3; 343 + 344 + tmp32 = rtw_read32(rtwdev, REG_MU_TX_CTL); 345 + /* Enable P1 aggr new packet according to P0 transfer time */ 346 + tmp32 |= BIT_MU_P1_WAIT_STATE_EN; 347 + /* MU Retry Limit */ 348 + tmp32 &= ~BIT_MASK_R_MU_RL; 349 + tmp32 |= (retry_limit << BIT_SHIFT_R_MU_RL) & BIT_MASK_R_MU_RL; 350 + /* Disable Tx MU-MIMO until sounding done */ 351 + tmp32 &= ~BIT_EN_MU_MIMO; 352 + /* Clear validity of MU STAs */ 353 + tmp32 &= ~BIT_MASK_R_MU_TABLE_VALID; 354 + rtw_write32(rtwdev, REG_MU_TX_CTL, tmp32); 355 + 356 + /* MU-MIMO Option as default value */ 357 + tmp8 = ack_policy << BIT_SHIFT_WMAC_TXMU_ACKPOLICY; 358 + tmp8 |= BIT_WMAC_TXMU_ACKPOLICY_EN; 359 + rtw_write8(rtwdev, REG_WMAC_MU_BF_OPTION, tmp8); 360 + 361 + /* MU-MIMO Control as default value */ 362 + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0); 363 + /* Set MU NDPA rate & BW source */ 364 + rtw_write32_set(rtwdev, REG_TXBF_CTRL, BIT_USE_NDPA_PARAMETER); 365 + /* Set NDPA Rate */ 366 + rtw_write8(rtwdev, REG_NDPA_OPT_CTRL, ndpa_rate); 367 + 368 + rtw_write32_mask(rtwdev, REG_BBPSF_CTRL, BIT_MASK_CSI_RATE, 369 + DESC_RATE6M); 370 + } 371 + 372 + void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, 373 + u8 fixrate_en, u8 *new_rate) 374 + { 375 + u32 csi_cfg; 376 + u16 cur_rrsr; 377 + 378 + csi_cfg = rtw_read32(rtwdev, REG_BBPSF_CTRL) & ~BIT_MASK_CSI_RATE; 379 + cur_rrsr = rtw_read16(rtwdev, REG_RRSR); 380 + 381 + if (rssi >= 40) { 382 + if (cur_rate != DESC_RATE54M) { 383 + cur_rrsr |= BIT(DESC_RATE54M); 384 + csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) << 385 + BIT_SHIFT_CSI_RATE; 386 + rtw_write16(rtwdev, REG_RRSR, cur_rrsr); 387 + rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg); 388 + } 389 + *new_rate = DESC_RATE54M; 390 + } else { 391 + if (cur_rate != DESC_RATE24M) { 392 + cur_rrsr &= ~BIT(DESC_RATE54M); 393 + csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) << 394 + BIT_SHIFT_CSI_RATE; 395 + rtw_write16(rtwdev, REG_RRSR, cur_rrsr); 396 + rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg); 397 + } 398 + *new_rate = DESC_RATE24M; 399 + } 400 + }
+92
drivers/net/wireless/realtek/rtw88/bf.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 2 + /* Copyright(c) 2018-2019 Realtek Corporation. 3 + */ 4 + 5 + #ifndef __RTW_BF_H_ 6 + #define __RTW_BF_H_ 7 + 8 + #define REG_TXBF_CTRL 0x042C 9 + #define REG_RRSR 0x0440 10 + #define REG_NDPA_OPT_CTRL 0x045F 11 + 12 + #define REG_ASSOCIATED_BFMER0_INFO 0x06E4 13 + #define REG_ASSOCIATED_BFMER1_INFO 0x06EC 14 + #define REG_TX_CSI_RPT_PARAM_BW20 0x06F4 15 + #define REG_SND_PTCL_CTRL 0x0718 16 + #define REG_MU_TX_CTL 0x14C0 17 + #define REG_MU_STA_GID_VLD 0x14C4 18 + #define REG_MU_STA_USER_POS_INFO 0x14C8 19 + #define REG_CSI_RRSR 0x1678 20 + #define REG_WMAC_MU_BF_OPTION 0x167C 21 + #define REG_WMAC_MU_BF_CTL 0x1680 22 + 23 + #define BIT_WMAC_USE_NDPARATE BIT(30) 24 + #define BIT_WMAC_TXMU_ACKPOLICY_EN BIT(6) 25 + #define BIT_USE_NDPA_PARAMETER BIT(30) 26 + #define BIT_MU_P1_WAIT_STATE_EN BIT(16) 27 + #define BIT_EN_MU_MIMO BIT(7) 28 + 29 + #define R_MU_RL 0xf 30 + #define BIT_SHIFT_R_MU_RL 12 31 + #define BIT_SHIFT_WMAC_TXMU_ACKPOLICY 4 32 + #define BIT_SHIFT_CSI_RATE 24 33 + 34 + #define BIT_MASK_R_MU_RL (R_MU_RL << BIT_SHIFT_R_MU_RL) 35 + #define BIT_MASK_R_MU_TABLE_VALID 0x3f 36 + #define BIT_MASK_CSI_RATE_VAL 0x3F 37 + #define BIT_MASK_CSI_RATE (BIT_MASK_CSI_RATE_VAL << BIT_SHIFT_CSI_RATE) 38 + 39 + #define BIT_RXFLTMAP0_ACTIONNOACK BIT(14) 40 + #define BIT_RXFLTMAP1_BF (BIT(4) | BIT(5)) 41 + #define BIT_RXFLTMAP1_BF_REPORT_POLL BIT(4) 42 + #define BIT_RXFLTMAP4_BF_REPORT_POLL BIT(4) 43 + 44 + #define RTW_NDP_RX_STANDBY_TIME 0x70 45 + #define RTW_SND_CTRL_REMOVE 0xD8 46 + #define RTW_SND_CTRL_SOUNDING 0xDB 47 + 48 + enum csi_seg_len { 49 + HAL_CSI_SEG_4K = 0, 50 + HAL_CSI_SEG_8K = 1, 51 + HAL_CSI_SEG_11K = 2, 52 + }; 53 + 54 + struct cfg_mumimo_para { 55 + u8 sounding_sts[6]; 56 + u16 grouping_bitmap; 57 + u8 mu_tx_en; 58 + u32 given_gid_tab[2]; 59 + u32 given_user_pos[4]; 60 + }; 61 + 62 + struct mu_bfer_init_para { 63 + u16 paid; 64 + u16 csi_para; 65 + u16 my_aid; 66 + enum csi_seg_len csi_length_sel; 67 + u8 bfer_address[ETH_ALEN]; 68 + }; 69 + 70 + void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 71 + struct ieee80211_bss_conf *bss_conf); 72 + void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 73 + struct ieee80211_bss_conf *bss_conf); 74 + void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, 75 + struct mu_bfer_init_para *param); 76 + void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif, 77 + enum rtw_trx_desc_rate rate); 78 + void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param); 79 + void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev); 80 + void rtw_bf_del_sounding(struct rtw_dev *rtwdev); 81 + void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, 82 + struct rtw_bfee *bfee); 83 + void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, 84 + struct rtw_bfee *bfee); 85 + void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, struct rtw_bfee *bfee); 86 + void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, struct rtw_bfee *bfee); 87 + void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 88 + struct ieee80211_bss_conf *conf); 89 + void rtw_bf_phy_init(struct rtw_dev *rtwdev); 90 + void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, 91 + u8 fixrate_en, u8 *new_rate); 92 + #endif
+1
drivers/net/wireless/realtek/rtw88/debug.h
··· 17 17 RTW_DBG_REGD = 0x00000100, 18 18 RTW_DBG_DEBUGFS = 0x00000200, 19 19 RTW_DBG_PS = 0x00000400, 20 + RTW_DBG_BF = 0x00000800, 20 21 21 22 RTW_DBG_ALL = 0xffffffff 22 23 };
+11
drivers/net/wireless/realtek/rtw88/mac80211.c
··· 10 10 #include "coex.h" 11 11 #include "ps.h" 12 12 #include "reg.h" 13 + #include "bf.h" 13 14 #include "debug.h" 14 15 15 16 static void rtw_ops_tx(struct ieee80211_hw *hw, ··· 158 157 rtwvif->stats.tx_cnt = 0; 159 158 rtwvif->stats.rx_cnt = 0; 160 159 rtwvif->in_lps = false; 160 + memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee)); 161 161 rtwvif->conf = &rtw_vif_port[port]; 162 162 rtw_txq_init(rtwdev, vif->txq); 163 163 ··· 350 348 rtw_fw_download_rsvd_page(rtwdev, vif); 351 349 rtw_send_rsvd_page_h2c(rtwdev); 352 350 rtw_coex_media_status_notify(rtwdev, conf->assoc); 351 + if (rtw_bf_support) 352 + rtw_bf_assoc(rtwdev, vif, conf); 353 353 } else { 354 354 rtw_leave_lps(rtwdev); 355 355 net_type = RTW_NET_NO_LINK; 356 356 rtwvif->aid = 0; 357 357 rtw_reset_rsvd_page(rtwdev); 358 + rtw_bf_disassoc(rtwdev, vif, conf); 358 359 } 359 360 360 361 rtwvif->net_type = net_type; ··· 372 367 373 368 if (changed & BSS_CHANGED_BEACON) 374 369 rtw_fw_download_rsvd_page(rtwdev, vif); 370 + 371 + if (changed & BSS_CHANGED_MU_GROUPS) { 372 + struct rtw_chip_info *chip = rtwdev->chip; 373 + 374 + chip->ops->set_gid_table(rtwdev, vif, conf); 375 + } 375 376 376 377 if (changed & BSS_CHANGED_ERP_SLOT) 377 378 rtw_conf_tx(rtwdev, rtwvif);
+38
drivers/net/wireless/realtek/rtw88/main.c
··· 14 14 #include "efuse.h" 15 15 #include "tx.h" 16 16 #include "debug.h" 17 + #include "bf.h" 17 18 18 19 unsigned int rtw_fw_lps_deep_mode; 19 20 EXPORT_SYMBOL(rtw_fw_lps_deep_mode); 21 + bool rtw_bf_support = true; 20 22 unsigned int rtw_debug_mask; 21 23 EXPORT_SYMBOL(rtw_debug_mask); 22 24 23 25 module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644); 26 + module_param_named(support_bf, rtw_bf_support, bool, 0644); 24 27 module_param_named(debug_mask, rtw_debug_mask, uint, 0644); 25 28 26 29 MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled"); 30 + MODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support"); 27 31 MODULE_PARM_DESC(debug_mask, "Debugging mask"); 28 32 29 33 static struct ieee80211_channel rtw_channeltable_2g[] = { ··· 130 126 }; 131 127 132 128 struct rtw_watch_dog_iter_data { 129 + struct rtw_dev *rtwdev; 133 130 struct rtw_vif *rtwvif; 134 131 }; 132 + 133 + static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 134 + { 135 + struct rtw_bf_info *bf_info = &rtwdev->bf_info; 136 + struct rtw_chip_info *chip = rtwdev->chip; 137 + u8 fix_rate_enable = 0; 138 + u8 new_csi_rate_idx; 139 + 140 + if (rtwvif->bfee.role != RTW_BFEE_SU && 141 + rtwvif->bfee.role != RTW_BFEE_MU) 142 + return; 143 + 144 + chip->ops->cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi, 145 + bf_info->cur_csi_rpt_rate, 146 + fix_rate_enable, &new_csi_rate_idx); 147 + 148 + if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate) 149 + bf_info->cur_csi_rpt_rate = new_csi_rate_idx; 150 + } 135 151 136 152 static void rtw_vif_watch_dog_iter(void *data, u8 *mac, 137 153 struct ieee80211_vif *vif) ··· 162 138 if (vif->type == NL80211_IFTYPE_STATION) 163 139 if (vif->bss_conf.assoc) 164 140 iter_data->rtwvif = rtwvif; 141 + 142 + rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); 165 143 166 144 rtwvif->stats.tx_unicast = 0; 167 145 rtwvif->stats.rx_unicast = 0; ··· 218 192 219 193 rtw_phy_dynamic_mechanism(rtwdev); 220 194 195 + data.rtwdev = rtwdev; 221 196 /* use atomic version to avoid taking local->iflist_mtx mutex */ 222 197 rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); 223 198 ··· 897 870 IEEE80211_VHT_CAP_HTC_VHT | 898 871 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | 899 872 0; 873 + 874 + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | 875 + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; 876 + vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << 877 + IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); 878 + 900 879 mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 901 880 IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | 902 881 IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | ··· 1037 1004 1038 1005 /* default use ack */ 1039 1006 rtwdev->hal.rcr |= BIT_VHT_DACK; 1007 + 1008 + hal->bfee_sts_cap = 3; 1040 1009 1041 1010 return ret; 1042 1011 } ··· 1376 1341 rtw_err(rtwdev, "regulatory_hint fail\n"); 1377 1342 1378 1343 rtw_debugfs_init(rtwdev); 1344 + 1345 + rtwdev->bf_info.bfer_mu_cnt = 0; 1346 + rtwdev->bf_info.bfer_su_cnt = 0; 1379 1347 1380 1348 return 0; 1381 1349 }
+43
drivers/net/wireless/realtek/rtw88/main.h
··· 29 29 #define RTW_RF_PATH_MAX 4 30 30 #define HW_FEATURE_LEN 13 31 31 32 + extern bool rtw_bf_support; 32 33 extern unsigned int rtw_fw_lps_deep_mode; 33 34 extern unsigned int rtw_debug_mask; 34 35 extern const struct ieee80211_ops rtw_ops; ··· 648 647 struct rtw_ra_report ra_report; 649 648 }; 650 649 650 + enum rtw_bfee_role { 651 + RTW_BFEE_NONE, 652 + RTW_BFEE_SU, 653 + RTW_BFEE_MU 654 + }; 655 + 656 + struct rtw_bfee { 657 + enum rtw_bfee_role role; 658 + 659 + u16 p_aid; 660 + u8 g_id; 661 + u8 mac_addr[ETH_ALEN]; 662 + u8 sound_dim; 663 + 664 + /* SU-MIMO */ 665 + u8 su_reg_index; 666 + 667 + /* MU-MIMO */ 668 + u16 aid; 669 + }; 670 + 671 + struct rtw_bf_info { 672 + u8 bfer_mu_cnt; 673 + u8 bfer_su_cnt; 674 + DECLARE_BITMAP(bfer_su_reg_maping, 2); 675 + u8 cur_csi_rpt_rate; 676 + }; 677 + 651 678 struct rtw_vif { 652 679 struct ieee80211_vif *vif; 653 680 enum rtw_net_type net_type; ··· 689 660 690 661 struct rtw_traffic_stats stats; 691 662 bool in_lps; 663 + 664 + struct rtw_bfee bfee; 692 665 }; 693 666 694 667 struct rtw_regulatory { ··· 723 692 void (*dpk_track)(struct rtw_dev *rtwdev); 724 693 void (*cck_pd_set)(struct rtw_dev *rtwdev, u8 level); 725 694 void (*pwr_track)(struct rtw_dev *rtwdev); 695 + void (*config_bfee)(struct rtw_dev *rtwdev, struct rtw_vif *vif, 696 + struct rtw_bfee *bfee, bool enable); 697 + void (*set_gid_table)(struct rtw_dev *rtwdev, 698 + struct ieee80211_vif *vif, 699 + struct ieee80211_bss_conf *conf); 700 + void (*cfg_csi_rate)(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, 701 + u8 fixrate_en, u8 *new_rate); 726 702 727 703 /* for coex */ 728 704 void (*coex_set_init)(struct rtw_dev *rtwdev); ··· 987 949 u16 dpd_ratemask; 988 950 u8 iqk_threshold; 989 951 const struct rtw_pwr_track_tbl *pwr_track_tbl; 952 + 953 + u8 bfer_su_max_num; 954 + u8 bfer_mu_max_num; 990 955 991 956 /* coex paras */ 992 957 u32 coex_para_ver; ··· 1427 1386 u8 rf_path_num; 1428 1387 u8 antenna_tx; 1429 1388 u8 antenna_rx; 1389 + u8 bfee_sts_cap; 1430 1390 1431 1391 /* protect tx power section */ 1432 1392 struct mutex tx_power_mutex; ··· 1465 1423 struct rtw_sec_desc sec; 1466 1424 struct rtw_traffic_stats stats; 1467 1425 struct rtw_regulatory regd; 1426 + struct rtw_bf_info bf_info; 1468 1427 1469 1428 struct rtw_dm_info dm_info; 1470 1429 struct rtw_coex coex;
+1
drivers/net/wireless/realtek/rtw88/reg.h
··· 326 326 #define REG_RXFLTMAP0 0x06A0 327 327 #define REG_RXFLTMAP1 0x06A2 328 328 #define REG_RXFLTMAP2 0x06A4 329 + #define REG_RXFLTMAP4 0x068A 329 330 #define REG_BT_COEX_TABLE0 0x06C0 330 331 #define REG_BT_COEX_TABLE1 0x06C4 331 332 #define REG_BT_COEX_BRK_TABLE 0x06C8
+46
drivers/net/wireless/realtek/rtw88/rtw8822b.c
··· 13 13 #include "mac.h" 14 14 #include "reg.h" 15 15 #include "debug.h" 16 + #include "bf.h" 16 17 17 18 static void rtw8822b_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, 18 19 u8 rx_path, bool is_tx2_path); ··· 121 120 dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; 122 121 } 123 122 123 + static void rtw8822b_phy_bf_init(struct rtw_dev *rtwdev) 124 + { 125 + rtw_bf_phy_init(rtwdev); 126 + /* Grouping bitmap parameters */ 127 + rtw_write32(rtwdev, 0x1C94, 0xAFFFAFFF); 128 + } 129 + 124 130 static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) 125 131 { 126 132 struct rtw_hal *hal = &rtwdev->hal; ··· 160 152 161 153 rtw8822b_phy_rfe_init(rtwdev); 162 154 rtw8822b_pwrtrack_init(rtwdev); 155 + 156 + rtw8822b_phy_bf_init(rtwdev); 163 157 } 164 158 165 159 #define WLAN_SLOT_TIME 0x09 ··· 1466 1456 dm_info->pwr_trk_triggered = false; 1467 1457 } 1468 1458 1459 + static void rtw8822b_bf_config_bfee_su(struct rtw_dev *rtwdev, 1460 + struct rtw_vif *vif, 1461 + struct rtw_bfee *bfee, bool enable) 1462 + { 1463 + if (enable) 1464 + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); 1465 + else 1466 + rtw_bf_remove_bfee_su(rtwdev, bfee); 1467 + } 1468 + 1469 + static void rtw8822b_bf_config_bfee_mu(struct rtw_dev *rtwdev, 1470 + struct rtw_vif *vif, 1471 + struct rtw_bfee *bfee, bool enable) 1472 + { 1473 + if (enable) 1474 + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); 1475 + else 1476 + rtw_bf_remove_bfee_mu(rtwdev, bfee); 1477 + } 1478 + 1479 + static void rtw8822b_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, 1480 + struct rtw_bfee *bfee, bool enable) 1481 + { 1482 + if (bfee->role == RTW_BFEE_SU) 1483 + rtw8822b_bf_config_bfee_su(rtwdev, vif, bfee, enable); 1484 + else if (bfee->role == RTW_BFEE_MU) 1485 + rtw8822b_bf_config_bfee_mu(rtwdev, vif, bfee, enable); 1486 + else 1487 + rtw_warn(rtwdev, "wrong bfee role\n"); 1488 + } 1489 + 1469 1490 static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { 1470 1491 {0x0086, 1471 1492 RTW_PWR_CUT_ALL_MSK, ··· 2044 2003 .false_alarm_statistics = rtw8822b_false_alarm_statistics, 2045 2004 .phy_calibration = rtw8822b_phy_calibration, 2046 2005 .pwr_track = rtw8822b_pwr_track, 2006 + .config_bfee = rtw8822b_bf_config_bfee, 2007 + .set_gid_table = rtw_bf_set_gid_table, 2008 + .cfg_csi_rate = rtw_bf_cfg_csi_rate, 2047 2009 2048 2010 .coex_set_init = rtw8822b_coex_cfg_init, 2049 2011 .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, ··· 2364 2320 .rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs), 2365 2321 .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl, 2366 2322 .iqk_threshold = 8, 2323 + .bfer_su_max_num = 2, 2324 + .bfer_mu_max_num = 1, 2367 2325 2368 2326 .coex_para_ver = 0x19062706, 2369 2327 .bt_desired_ver = 0x6,
+59
drivers/net/wireless/realtek/rtw88/rtw8822c.c
··· 14 14 #include "reg.h" 15 15 #include "debug.h" 16 16 #include "util.h" 17 + #include "bf.h" 17 18 18 19 static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, 19 20 u8 rx_path, bool is_tx2_path); ··· 1069 1068 1070 1069 rtw8822c_rf_init(rtwdev); 1071 1070 rtw8822c_pwrtrack_init(rtwdev); 1071 + 1072 + rtw_bf_phy_init(rtwdev); 1072 1073 } 1073 1074 1074 1075 #define WLAN_TXQ_RPT_EN 0x1F ··· 2079 2076 rtw_write_rf(rtwdev, RF_PATH_A, 0x1d, 0xfffff, 0x0); 2080 2077 rtw_write_rf(rtwdev, RF_PATH_B, 0x1d, 0xfffff, 0x0); 2081 2078 } 2079 + } 2080 + 2081 + static void rtw8822c_bf_enable_bfee_su(struct rtw_dev *rtwdev, 2082 + struct rtw_vif *vif, 2083 + struct rtw_bfee *bfee) 2084 + { 2085 + u8 csi_rsc = 0; 2086 + u32 tmp6dc; 2087 + 2088 + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); 2089 + 2090 + tmp6dc = rtw_read32(rtwdev, REG_BBPSF_CTRL) | 2091 + BIT_WMAC_USE_NDPARATE | 2092 + (csi_rsc << 13); 2093 + if (vif->net_type == RTW_NET_AP_MODE) 2094 + rtw_write32(rtwdev, REG_BBPSF_CTRL, tmp6dc | BIT(12)); 2095 + else 2096 + rtw_write32(rtwdev, REG_BBPSF_CTRL, tmp6dc & ~BIT(12)); 2097 + 2098 + rtw_write32(rtwdev, REG_CSI_RRSR, 0x550); 2099 + } 2100 + 2101 + static void rtw8822c_bf_config_bfee_su(struct rtw_dev *rtwdev, 2102 + struct rtw_vif *vif, 2103 + struct rtw_bfee *bfee, bool enable) 2104 + { 2105 + if (enable) 2106 + rtw8822c_bf_enable_bfee_su(rtwdev, vif, bfee); 2107 + else 2108 + rtw_bf_remove_bfee_su(rtwdev, bfee); 2109 + } 2110 + 2111 + static void rtw8822c_bf_config_bfee_mu(struct rtw_dev *rtwdev, 2112 + struct rtw_vif *vif, 2113 + struct rtw_bfee *bfee, bool enable) 2114 + { 2115 + if (enable) 2116 + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); 2117 + else 2118 + rtw_bf_remove_bfee_mu(rtwdev, bfee); 2119 + } 2120 + 2121 + static void rtw8822c_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, 2122 + struct rtw_bfee *bfee, bool enable) 2123 + { 2124 + if (bfee->role == RTW_BFEE_SU) 2125 + rtw8822c_bf_config_bfee_su(rtwdev, vif, bfee, enable); 2126 + else if (bfee->role == RTW_BFEE_MU) 2127 + rtw8822c_bf_config_bfee_mu(rtwdev, vif, bfee, enable); 2128 + else 2129 + rtw_warn(rtwdev, "wrong bfee role\n"); 2082 2130 } 2083 2131 2084 2132 struct dpk_cfg_pair { ··· 3732 3678 .phy_calibration = rtw8822c_phy_calibration, 3733 3679 .cck_pd_set = rtw8822c_phy_cck_pd_set, 3734 3680 .pwr_track = rtw8822c_pwr_track, 3681 + .config_bfee = rtw8822c_bf_config_bfee, 3682 + .set_gid_table = rtw_bf_set_gid_table, 3683 + .cfg_csi_rate = rtw_bf_cfg_csi_rate, 3735 3684 3736 3685 .coex_set_init = rtw8822c_coex_cfg_init, 3737 3686 .coex_set_ant_switch = NULL, ··· 4055 3998 .dpd_ratemask = DIS_DPD_RATEALL, 4056 3999 .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl, 4057 4000 .iqk_threshold = 8, 4001 + .bfer_su_max_num = 2, 4002 + .bfer_mu_max_num = 1, 4058 4003 4059 4004 .coex_para_ver = 0x19062706, 4060 4005 .bt_desired_ver = 0x6,