517 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 10static 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 20static 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 else55 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 else124 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 else154 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 174static 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 206static 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 236static 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 252static 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 283static 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 304static 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 333static 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 346static 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 384bool 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}433EXPORT_SYMBOL_GPL(rtl92d_rx_query_desc);434 435void 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}476EXPORT_SYMBOL_GPL(rtl92d_set_desc);477 478u64 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}516EXPORT_SYMBOL_GPL(rtl92d_get_desc);517