1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2009-2012 Realtek Corporation.*/ 3 4 #include "wifi.h" 5 #include "stats.h" 6 #include <linux/export.h> 7 8 u8 rtl_query_rxpwrpercentage(s8 antpower) 9 { 10 if ((antpower <= -100) || (antpower >= 20)) 11 return 0; 12 else if (antpower >= 0) 13 return 100; 14 else 15 return 100 + antpower; 16 } 17 EXPORT_SYMBOL(rtl_query_rxpwrpercentage); 18 19 u8 rtl_evm_db_to_percentage(s8 value) 20 { 21 s8 ret_val = clamp(-value, 0, 33) * 3; 22 23 if (ret_val == 99) 24 ret_val = 100; 25 26 return ret_val; 27 } 28 EXPORT_SYMBOL(rtl_evm_db_to_percentage); 29 30 static long rtl_translate_todbm(struct ieee80211_hw *hw, 31 u8 signal_strength_index) 32 { 33 long signal_power; 34 35 signal_power = (long)((signal_strength_index + 1) >> 1); 36 signal_power -= 95; 37 return signal_power; 38 } 39 40 long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig) 41 { 42 long retsig; 43 44 if (currsig >= 61 && currsig <= 100) 45 retsig = 90 + ((currsig - 60) / 4); 46 else if (currsig >= 41 && currsig <= 60) 47 retsig = 78 + ((currsig - 40) / 2); 48 else if (currsig >= 31 && currsig <= 40) 49 retsig = 66 + (currsig - 30); 50 else if (currsig >= 21 && currsig <= 30) 51 retsig = 54 + (currsig - 20); 52 else if (currsig >= 5 && currsig <= 20) 53 retsig = 42 + (((currsig - 5) * 2) / 3); 54 else if (currsig == 4) 55 retsig = 36; 56 else if (currsig == 3) 57 retsig = 27; 58 else if (currsig == 2) 59 retsig = 18; 60 else if (currsig == 1) 61 retsig = 9; 62 else 63 retsig = currsig; 64 65 return retsig; 66 } 67 EXPORT_SYMBOL(rtl_signal_scale_mapping); 68 69 static void rtl_process_ui_rssi(struct ieee80211_hw *hw, 70 struct rtl_stats *pstatus) 71 { 72 struct rtl_priv *rtlpriv = rtl_priv(hw); 73 struct rtl_phy *rtlphy = &(rtlpriv->phy); 74 u8 rfpath; 75 u32 last_rssi, tmpval; 76 77 if (!pstatus->packet_toself && !pstatus->packet_beacon) 78 return; 79 80 rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all; 81 rtlpriv->stats.rssi_calculate_cnt++; 82 83 if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { 84 rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; 85 last_rssi = rtlpriv->stats.ui_rssi.elements[ 86 rtlpriv->stats.ui_rssi.index]; 87 rtlpriv->stats.ui_rssi.total_val -= last_rssi; 88 } 89 rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength; 90 rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] = 91 pstatus->signalstrength; 92 if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) 93 rtlpriv->stats.ui_rssi.index = 0; 94 tmpval = rtlpriv->stats.ui_rssi.total_val / 95 rtlpriv->stats.ui_rssi.total_num; 96 rtlpriv->stats.signal_strength = rtl_translate_todbm(hw, 97 (u8) tmpval); 98 pstatus->rssi = rtlpriv->stats.signal_strength; 99 100 if (pstatus->is_cck) 101 return; 102 103 for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; 104 rfpath++) { 105 if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { 106 rtlpriv->stats.rx_rssi_percentage[rfpath] = 107 pstatus->rx_mimo_signalstrength[rfpath]; 108 109 } 110 if (pstatus->rx_mimo_signalstrength[rfpath] > 111 rtlpriv->stats.rx_rssi_percentage[rfpath]) { 112 rtlpriv->stats.rx_rssi_percentage[rfpath] = 113 ((rtlpriv->stats.rx_rssi_percentage[rfpath] * 114 (RX_SMOOTH_FACTOR - 1)) + 115 (pstatus->rx_mimo_signalstrength[rfpath])) / 116 (RX_SMOOTH_FACTOR); 117 rtlpriv->stats.rx_rssi_percentage[rfpath] = 118 rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; 119 } else { 120 rtlpriv->stats.rx_rssi_percentage[rfpath] = 121 ((rtlpriv->stats.rx_rssi_percentage[rfpath] * 122 (RX_SMOOTH_FACTOR - 1)) + 123 (pstatus->rx_mimo_signalstrength[rfpath])) / 124 (RX_SMOOTH_FACTOR); 125 } 126 rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath]; 127 rtlpriv->stats.rx_evm_dbm[rfpath] = 128 pstatus->rx_mimo_evm_dbm[rfpath]; 129 rtlpriv->stats.rx_cfo_short[rfpath] = 130 pstatus->cfo_short[rfpath]; 131 rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath]; 132 } 133 } 134 135 static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw, 136 struct rtl_stats *pstatus) 137 { 138 struct rtl_priv *rtlpriv = rtl_priv(hw); 139 int weighting = 0; 140 141 if (rtlpriv->stats.recv_signal_power == 0) 142 rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower; 143 if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power) 144 weighting = 5; 145 else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power) 146 weighting = (-5); 147 rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 148 5 + pstatus->recvsignalpower + weighting) / 6; 149 } 150 151 static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) 152 { 153 struct rtl_priv *rtlpriv = rtl_priv(hw); 154 struct rtl_sta_info *drv_priv = NULL; 155 struct ieee80211_sta *sta = NULL; 156 long undec_sm_pwdb; 157 158 rcu_read_lock(); 159 if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) 160 sta = rtl_find_sta(hw, pstatus->psaddr); 161 162 /* adhoc or ap mode */ 163 if (sta) { 164 drv_priv = (struct rtl_sta_info *) sta->drv_priv; 165 undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb; 166 } else { 167 undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; 168 } 169 170 if (undec_sm_pwdb < 0) 171 undec_sm_pwdb = pstatus->rx_pwdb_all; 172 if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) { 173 undec_sm_pwdb = (((undec_sm_pwdb) * 174 (RX_SMOOTH_FACTOR - 1)) + 175 (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); 176 undec_sm_pwdb = undec_sm_pwdb + 1; 177 } else { 178 undec_sm_pwdb = (((undec_sm_pwdb) * 179 (RX_SMOOTH_FACTOR - 1)) + 180 (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); 181 } 182 183 if (sta) { 184 drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb; 185 } else { 186 rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb; 187 } 188 rcu_read_unlock(); 189 190 rtl_update_rxsignalstatistics(hw, pstatus); 191 } 192 193 static void rtl_process_ui_link_quality(struct ieee80211_hw *hw, 194 struct rtl_stats *pstatus) 195 { 196 struct rtl_priv *rtlpriv = rtl_priv(hw); 197 u32 last_evm, n_stream, tmpval; 198 199 if (pstatus->signalquality == 0) 200 return; 201 202 if (rtlpriv->stats.ui_link_quality.total_num++ >= 203 PHY_LINKQUALITY_SLID_WIN_MAX) { 204 rtlpriv->stats.ui_link_quality.total_num = 205 PHY_LINKQUALITY_SLID_WIN_MAX; 206 last_evm = rtlpriv->stats.ui_link_quality.elements[ 207 rtlpriv->stats.ui_link_quality.index]; 208 rtlpriv->stats.ui_link_quality.total_val -= last_evm; 209 } 210 rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality; 211 rtlpriv->stats.ui_link_quality.elements[ 212 rtlpriv->stats.ui_link_quality.index++] = 213 pstatus->signalquality; 214 if (rtlpriv->stats.ui_link_quality.index >= 215 PHY_LINKQUALITY_SLID_WIN_MAX) 216 rtlpriv->stats.ui_link_quality.index = 0; 217 tmpval = rtlpriv->stats.ui_link_quality.total_val / 218 rtlpriv->stats.ui_link_quality.total_num; 219 rtlpriv->stats.signal_quality = tmpval; 220 rtlpriv->stats.last_sigstrength_inpercent = tmpval; 221 for (n_stream = 0; n_stream < 2; n_stream++) { 222 if (pstatus->rx_mimo_sig_qual[n_stream] != -1) { 223 if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) { 224 rtlpriv->stats.rx_evm_percentage[n_stream] = 225 pstatus->rx_mimo_sig_qual[n_stream]; 226 } 227 rtlpriv->stats.rx_evm_percentage[n_stream] = 228 ((rtlpriv->stats.rx_evm_percentage[n_stream] 229 * (RX_SMOOTH_FACTOR - 1)) + 230 (pstatus->rx_mimo_sig_qual[n_stream] * 1)) / 231 (RX_SMOOTH_FACTOR); 232 } 233 } 234 } 235 236 void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, 237 struct rtl_stats *pstatus) 238 { 239 240 if (!pstatus->packet_matchbssid) 241 return; 242 243 rtl_process_ui_rssi(hw, pstatus); 244 rtl_process_pwdb(hw, pstatus); 245 rtl_process_ui_link_quality(hw, pstatus); 246 } 247 EXPORT_SYMBOL(rtl_process_phyinfo); 248