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