1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2009-2012 Realtek Corporation.*/ 3 4 #include "../wifi.h" 5 #include "../base.h" 6 #include "../stats.h" 7 #include "def.h" 8 #include "trx_common.h" 9 10 static long _rtl92d_translate_todbm(struct ieee80211_hw *hw, 11 u8 signal_strength_index) 12 { 13 long signal_power; 14 15 signal_power = (long)((signal_strength_index + 1) >> 1); 16 signal_power -= 95; 17 return signal_power; 18 } 19 20 static void _rtl92d_query_rxphystatus(struct ieee80211_hw *hw, 21 struct rtl_stats *pstats, 22 __le32 *pdesc, 23 struct rx_fwinfo_92d *p_drvinfo, 24 bool packet_match_bssid, 25 bool packet_toself, 26 bool packet_beacon) 27 { 28 struct rtl_priv *rtlpriv = rtl_priv(hw); 29 struct rtl_phy *rtlphy = &rtlpriv->phy; 30 struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); 31 struct phy_sts_cck_8192d *cck_buf; 32 s8 rx_pwr_all, rx_pwr[4]; 33 u8 rf_rx_num = 0, evm, pwdb_all; 34 u8 i, max_spatial_stream; 35 u32 rssi, total_rssi = 0; 36 bool is_cck_rate; 37 u8 rxmcs; 38 39 rxmcs = get_rx_desc_rxmcs(pdesc); 40 is_cck_rate = rxmcs <= DESC_RATE11M; 41 pstats->packet_matchbssid = packet_match_bssid; 42 pstats->packet_toself = packet_toself; 43 pstats->packet_beacon = packet_beacon; 44 pstats->is_cck = is_cck_rate; 45 pstats->rx_mimo_sig_qual[0] = -1; 46 pstats->rx_mimo_sig_qual[1] = -1; 47 48 if (is_cck_rate) { 49 u8 report, cck_highpwr; 50 51 cck_buf = (struct phy_sts_cck_8192d *)p_drvinfo; 52 if (ppsc->rfpwr_state == ERFON) 53 cck_highpwr = rtlphy->cck_high_power; 54 else 55 cck_highpwr = false; 56 if (!cck_highpwr) { 57 u8 cck_agc_rpt = cck_buf->cck_agc_rpt; 58 59 report = cck_buf->cck_agc_rpt & 0xc0; 60 report = report >> 6; 61 switch (report) { 62 case 0x3: 63 rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); 64 break; 65 case 0x2: 66 rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); 67 break; 68 case 0x1: 69 rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); 70 break; 71 case 0x0: 72 rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); 73 break; 74 } 75 } else { 76 u8 cck_agc_rpt = cck_buf->cck_agc_rpt; 77 78 report = p_drvinfo->cfosho[0] & 0x60; 79 report = report >> 5; 80 switch (report) { 81 case 0x3: 82 rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); 83 break; 84 case 0x2: 85 rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); 86 break; 87 case 0x1: 88 rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); 89 break; 90 case 0x0: 91 rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); 92 break; 93 } 94 } 95 pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); 96 /* CCK gain is smaller than OFDM/MCS gain, */ 97 /* so we add gain diff by experiences, the val is 6 */ 98 pwdb_all += 6; 99 if (pwdb_all > 100) 100 pwdb_all = 100; 101 /* modify the offset to make the same gain index with OFDM. */ 102 if (pwdb_all > 34 && pwdb_all <= 42) 103 pwdb_all -= 2; 104 else if (pwdb_all > 26 && pwdb_all <= 34) 105 pwdb_all -= 6; 106 else if (pwdb_all > 14 && pwdb_all <= 26) 107 pwdb_all -= 8; 108 else if (pwdb_all > 4 && pwdb_all <= 14) 109 pwdb_all -= 4; 110 pstats->rx_pwdb_all = pwdb_all; 111 pstats->recvsignalpower = rx_pwr_all; 112 if (packet_match_bssid) { 113 u8 sq; 114 115 if (pstats->rx_pwdb_all > 40) { 116 sq = 100; 117 } else { 118 sq = cck_buf->sq_rpt; 119 if (sq > 64) 120 sq = 0; 121 else if (sq < 20) 122 sq = 100; 123 else 124 sq = ((64 - sq) * 100) / 44; 125 } 126 pstats->signalquality = sq; 127 pstats->rx_mimo_sig_qual[0] = sq; 128 pstats->rx_mimo_sig_qual[1] = -1; 129 } 130 } else { 131 rtlpriv->dm.rfpath_rxenable[0] = true; 132 rtlpriv->dm.rfpath_rxenable[1] = true; 133 for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { 134 if (rtlpriv->dm.rfpath_rxenable[i]) 135 rf_rx_num++; 136 rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) 137 - 110; 138 rssi = rtl_query_rxpwrpercentage(rx_pwr[i]); 139 total_rssi += rssi; 140 rtlpriv->stats.rx_snr_db[i] = 141 (long)(p_drvinfo->rxsnr[i] / 2); 142 if (packet_match_bssid) 143 pstats->rx_mimo_signalstrength[i] = (u8)rssi; 144 } 145 rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 106; 146 pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); 147 pstats->rx_pwdb_all = pwdb_all; 148 pstats->rxpower = rx_pwr_all; 149 pstats->recvsignalpower = rx_pwr_all; 150 if (get_rx_desc_rxht(pdesc) && rxmcs >= DESC_RATEMCS8 && 151 rxmcs <= DESC_RATEMCS15) 152 max_spatial_stream = 2; 153 else 154 max_spatial_stream = 1; 155 for (i = 0; i < max_spatial_stream; i++) { 156 evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]); 157 if (packet_match_bssid) { 158 if (i == 0) 159 pstats->signalquality = 160 (u8)(evm & 0xff); 161 pstats->rx_mimo_sig_qual[i] = 162 (u8)(evm & 0xff); 163 } 164 } 165 } 166 if (is_cck_rate) 167 pstats->signalstrength = (u8)(rtl_signal_scale_mapping(hw, 168 pwdb_all)); 169 else if (rf_rx_num != 0) 170 pstats->signalstrength = (u8)(rtl_signal_scale_mapping(hw, 171 total_rssi /= rf_rx_num)); 172 } 173 174 static void rtl92d_loop_over_paths(struct ieee80211_hw *hw, 175 struct rtl_stats *pstats) 176 { 177 struct rtl_priv *rtlpriv = rtl_priv(hw); 178 struct rtl_phy *rtlphy = &rtlpriv->phy; 179 u8 rfpath; 180 181 for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; 182 rfpath++) { 183 if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { 184 rtlpriv->stats.rx_rssi_percentage[rfpath] = 185 pstats->rx_mimo_signalstrength[rfpath]; 186 } 187 if (pstats->rx_mimo_signalstrength[rfpath] > 188 rtlpriv->stats.rx_rssi_percentage[rfpath]) { 189 rtlpriv->stats.rx_rssi_percentage[rfpath] = 190 ((rtlpriv->stats.rx_rssi_percentage[rfpath] * 191 (RX_SMOOTH_FACTOR - 1)) + 192 (pstats->rx_mimo_signalstrength[rfpath])) / 193 (RX_SMOOTH_FACTOR); 194 rtlpriv->stats.rx_rssi_percentage[rfpath] = 195 rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; 196 } else { 197 rtlpriv->stats.rx_rssi_percentage[rfpath] = 198 ((rtlpriv->stats.rx_rssi_percentage[rfpath] * 199 (RX_SMOOTH_FACTOR - 1)) + 200 (pstats->rx_mimo_signalstrength[rfpath])) / 201 (RX_SMOOTH_FACTOR); 202 } 203 } 204 } 205 206 static void _rtl92d_process_ui_rssi(struct ieee80211_hw *hw, 207 struct rtl_stats *pstats) 208 { 209 struct rtl_priv *rtlpriv = rtl_priv(hw); 210 struct rt_smooth_data *ui_rssi; 211 u32 last_rssi, tmpval; 212 213 if (!pstats->packet_toself && !pstats->packet_beacon) 214 return; 215 216 ui_rssi = &rtlpriv->stats.ui_rssi; 217 218 rtlpriv->stats.rssi_calculate_cnt++; 219 if (ui_rssi->total_num++ >= PHY_RSSI_SLID_WIN_MAX) { 220 ui_rssi->total_num = PHY_RSSI_SLID_WIN_MAX; 221 last_rssi = ui_rssi->elements[ui_rssi->index]; 222 ui_rssi->total_val -= last_rssi; 223 } 224 ui_rssi->total_val += pstats->signalstrength; 225 ui_rssi->elements[ui_rssi->index++] = pstats->signalstrength; 226 if (ui_rssi->index >= PHY_RSSI_SLID_WIN_MAX) 227 ui_rssi->index = 0; 228 tmpval = ui_rssi->total_val / ui_rssi->total_num; 229 rtlpriv->stats.signal_strength = _rtl92d_translate_todbm(hw, (u8)tmpval); 230 pstats->rssi = rtlpriv->stats.signal_strength; 231 232 if (!pstats->is_cck && pstats->packet_toself) 233 rtl92d_loop_over_paths(hw, pstats); 234 } 235 236 static void _rtl92d_update_rxsignalstatistics(struct ieee80211_hw *hw, 237 struct rtl_stats *pstats) 238 { 239 struct rtl_priv *rtlpriv = rtl_priv(hw); 240 int weighting = 0; 241 242 if (rtlpriv->stats.recv_signal_power == 0) 243 rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; 244 if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) 245 weighting = 5; 246 else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) 247 weighting = (-5); 248 rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 249 5 + pstats->recvsignalpower + weighting) / 6; 250 } 251 252 static void _rtl92d_process_pwdb(struct ieee80211_hw *hw, 253 struct rtl_stats *pstats) 254 { 255 struct rtl_priv *rtlpriv = rtl_priv(hw); 256 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 257 long undec_sm_pwdb; 258 259 if (mac->opmode == NL80211_IFTYPE_ADHOC || 260 mac->opmode == NL80211_IFTYPE_AP) 261 return; 262 263 undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; 264 265 if (pstats->packet_toself || pstats->packet_beacon) { 266 if (undec_sm_pwdb < 0) 267 undec_sm_pwdb = pstats->rx_pwdb_all; 268 if (pstats->rx_pwdb_all > (u32)undec_sm_pwdb) { 269 undec_sm_pwdb = (((undec_sm_pwdb) * 270 (RX_SMOOTH_FACTOR - 1)) + 271 (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); 272 undec_sm_pwdb = undec_sm_pwdb + 1; 273 } else { 274 undec_sm_pwdb = (((undec_sm_pwdb) * 275 (RX_SMOOTH_FACTOR - 1)) + 276 (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); 277 } 278 rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb; 279 _rtl92d_update_rxsignalstatistics(hw, pstats); 280 } 281 } 282 283 static void rtl92d_loop_over_streams(struct ieee80211_hw *hw, 284 struct rtl_stats *pstats) 285 { 286 struct rtl_priv *rtlpriv = rtl_priv(hw); 287 int stream; 288 289 for (stream = 0; stream < 2; stream++) { 290 if (pstats->rx_mimo_sig_qual[stream] != -1) { 291 if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { 292 rtlpriv->stats.rx_evm_percentage[stream] = 293 pstats->rx_mimo_sig_qual[stream]; 294 } 295 rtlpriv->stats.rx_evm_percentage[stream] = 296 ((rtlpriv->stats.rx_evm_percentage[stream] 297 * (RX_SMOOTH_FACTOR - 1)) + 298 (pstats->rx_mimo_sig_qual[stream] * 1)) / 299 (RX_SMOOTH_FACTOR); 300 } 301 } 302 } 303 304 static void _rtl92d_process_ui_link_quality(struct ieee80211_hw *hw, 305 struct rtl_stats *pstats) 306 { 307 struct rtl_priv *rtlpriv = rtl_priv(hw); 308 struct rt_smooth_data *ui_link_quality; 309 u32 last_evm, tmpval; 310 311 if (pstats->signalquality == 0) 312 return; 313 if (!pstats->packet_toself && !pstats->packet_beacon) 314 return; 315 316 ui_link_quality = &rtlpriv->stats.ui_link_quality; 317 318 if (ui_link_quality->total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) { 319 ui_link_quality->total_num = PHY_LINKQUALITY_SLID_WIN_MAX; 320 last_evm = ui_link_quality->elements[ui_link_quality->index]; 321 ui_link_quality->total_val -= last_evm; 322 } 323 ui_link_quality->total_val += pstats->signalquality; 324 ui_link_quality->elements[ui_link_quality->index++] = pstats->signalquality; 325 if (ui_link_quality->index >= PHY_LINKQUALITY_SLID_WIN_MAX) 326 ui_link_quality->index = 0; 327 tmpval = ui_link_quality->total_val / ui_link_quality->total_num; 328 rtlpriv->stats.signal_quality = tmpval; 329 rtlpriv->stats.last_sigstrength_inpercent = tmpval; 330 rtl92d_loop_over_streams(hw, pstats); 331 } 332 333 static void _rtl92d_process_phyinfo(struct ieee80211_hw *hw, 334 u8 *buffer, 335 struct rtl_stats *pcurrent_stats) 336 { 337 if (!pcurrent_stats->packet_matchbssid && 338 !pcurrent_stats->packet_beacon) 339 return; 340 341 _rtl92d_process_ui_rssi(hw, pcurrent_stats); 342 _rtl92d_process_pwdb(hw, pcurrent_stats); 343 _rtl92d_process_ui_link_quality(hw, pcurrent_stats); 344 } 345 346 static void _rtl92d_translate_rx_signal_stuff(struct ieee80211_hw *hw, 347 struct sk_buff *skb, 348 struct rtl_stats *pstats, 349 __le32 *pdesc, 350 struct rx_fwinfo_92d *p_drvinfo) 351 { 352 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 353 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 354 struct ieee80211_hdr *hdr; 355 bool packet_matchbssid; 356 bool packet_beacon; 357 bool packet_toself; 358 u16 type, cfc; 359 u8 *tmp_buf; 360 u8 *praddr; 361 __le16 fc; 362 363 tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; 364 hdr = (struct ieee80211_hdr *)tmp_buf; 365 fc = hdr->frame_control; 366 cfc = le16_to_cpu(fc); 367 type = WLAN_FC_GET_TYPE(fc); 368 praddr = hdr->addr1; 369 packet_matchbssid = ((type != IEEE80211_FTYPE_CTL) && 370 ether_addr_equal(mac->bssid, 371 (cfc & IEEE80211_FCTL_TODS) ? hdr->addr1 : 372 (cfc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : 373 hdr->addr3) && 374 (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); 375 packet_toself = packet_matchbssid && 376 ether_addr_equal(praddr, rtlefuse->dev_addr); 377 packet_beacon = ieee80211_is_beacon(fc); 378 _rtl92d_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, 379 packet_matchbssid, packet_toself, 380 packet_beacon); 381 _rtl92d_process_phyinfo(hw, tmp_buf, pstats); 382 } 383 384 bool rtl92d_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, 385 struct ieee80211_rx_status *rx_status, 386 u8 *pdesc8, struct sk_buff *skb) 387 { 388 __le32 *pdesc = (__le32 *)pdesc8; 389 struct rx_fwinfo_92d *p_drvinfo; 390 u32 phystatus = get_rx_desc_physt(pdesc); 391 392 stats->length = (u16)get_rx_desc_pkt_len(pdesc); 393 stats->rx_drvinfo_size = (u8)get_rx_desc_drv_info_size(pdesc) * 394 RX_DRV_INFO_SIZE_UNIT; 395 stats->rx_bufshift = (u8)(get_rx_desc_shift(pdesc) & 0x03); 396 stats->icv = (u16)get_rx_desc_icv(pdesc); 397 stats->crc = (u16)get_rx_desc_crc32(pdesc); 398 stats->hwerror = (stats->crc | stats->icv); 399 stats->decrypted = !get_rx_desc_swdec(pdesc) && 400 get_rx_desc_enc_type(pdesc) != RX_DESC_ENC_NONE; 401 stats->rate = (u8)get_rx_desc_rxmcs(pdesc); 402 stats->shortpreamble = (u16)get_rx_desc_splcp(pdesc); 403 stats->isampdu = (bool)(get_rx_desc_paggr(pdesc) == 1); 404 stats->isfirst_ampdu = (bool)((get_rx_desc_paggr(pdesc) == 1) && 405 (get_rx_desc_faggr(pdesc) == 1)); 406 stats->timestamp_low = get_rx_desc_tsfl(pdesc); 407 stats->rx_is40mhzpacket = (bool)get_rx_desc_bw(pdesc); 408 stats->is_ht = (bool)get_rx_desc_rxht(pdesc); 409 rx_status->freq = hw->conf.chandef.chan->center_freq; 410 rx_status->band = hw->conf.chandef.chan->band; 411 if (get_rx_desc_crc32(pdesc)) 412 rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 413 if (get_rx_desc_bw(pdesc)) 414 rx_status->bw = RATE_INFO_BW_40; 415 if (get_rx_desc_rxht(pdesc)) 416 rx_status->encoding = RX_ENC_HT; 417 rx_status->flag |= RX_FLAG_MACTIME_START; 418 if (stats->decrypted) 419 rx_status->flag |= RX_FLAG_DECRYPTED; 420 rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, 421 false, stats->rate); 422 rx_status->mactime = get_rx_desc_tsfl(pdesc); 423 if (phystatus) { 424 p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + 425 stats->rx_bufshift); 426 _rtl92d_translate_rx_signal_stuff(hw, skb, stats, pdesc, 427 p_drvinfo); 428 } 429 /*rx_status->qual = stats->signal; */ 430 rx_status->signal = stats->recvsignalpower + 10; 431 return true; 432 } 433 EXPORT_SYMBOL_GPL(rtl92d_rx_query_desc); 434 435 void rtl92d_set_desc(struct ieee80211_hw *hw, u8 *pdesc8, bool istx, 436 u8 desc_name, u8 *val) 437 { 438 __le32 *pdesc = (__le32 *)pdesc8; 439 440 if (istx) { 441 switch (desc_name) { 442 case HW_DESC_OWN: 443 wmb(); 444 set_tx_desc_own(pdesc, 1); 445 break; 446 case HW_DESC_TX_NEXTDESC_ADDR: 447 set_tx_desc_next_desc_address(pdesc, *(u32 *)val); 448 break; 449 default: 450 WARN_ONCE(true, "rtl8192de: ERR txdesc :%d not processed\n", 451 desc_name); 452 break; 453 } 454 } else { 455 switch (desc_name) { 456 case HW_DESC_RXOWN: 457 wmb(); 458 set_rx_desc_own(pdesc, 1); 459 break; 460 case HW_DESC_RXBUFF_ADDR: 461 set_rx_desc_buff_addr(pdesc, *(u32 *)val); 462 break; 463 case HW_DESC_RXPKT_LEN: 464 set_rx_desc_pkt_len(pdesc, *(u32 *)val); 465 break; 466 case HW_DESC_RXERO: 467 set_rx_desc_eor(pdesc, 1); 468 break; 469 default: 470 WARN_ONCE(true, "rtl8192de: ERR rxdesc :%d not processed\n", 471 desc_name); 472 break; 473 } 474 } 475 } 476 EXPORT_SYMBOL_GPL(rtl92d_set_desc); 477 478 u64 rtl92d_get_desc(struct ieee80211_hw *hw, 479 u8 *p_desc8, bool istx, u8 desc_name) 480 { 481 __le32 *p_desc = (__le32 *)p_desc8; 482 u32 ret = 0; 483 484 if (istx) { 485 switch (desc_name) { 486 case HW_DESC_OWN: 487 ret = get_tx_desc_own(p_desc); 488 break; 489 case HW_DESC_TXBUFF_ADDR: 490 ret = get_tx_desc_tx_buffer_address(p_desc); 491 break; 492 default: 493 WARN_ONCE(true, "rtl8192de: ERR txdesc :%d not processed\n", 494 desc_name); 495 break; 496 } 497 } else { 498 switch (desc_name) { 499 case HW_DESC_OWN: 500 ret = get_rx_desc_own(p_desc); 501 break; 502 case HW_DESC_RXPKT_LEN: 503 ret = get_rx_desc_pkt_len(p_desc); 504 break; 505 case HW_DESC_RXBUFF_ADDR: 506 ret = get_rx_desc_buff_addr(p_desc); 507 break; 508 default: 509 WARN_ONCE(true, "rtl8192de: ERR rxdesc :%d not processed\n", 510 desc_name); 511 break; 512 } 513 } 514 return ret; 515 } 516 EXPORT_SYMBOL_GPL(rtl92d_get_desc); 517