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