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
8u8 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}
17EXPORT_SYMBOL(rtl_query_rxpwrpercentage);
18
19u8 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}
28EXPORT_SYMBOL(rtl_evm_db_to_percentage);
29
30static 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
40long 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}
67EXPORT_SYMBOL(rtl_signal_scale_mapping);
68
69static 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
135static 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
151static 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
193static 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
236void 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}
247EXPORT_SYMBOL(rtl_process_phyinfo);
248