xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: wlan_hdd_stats.c
22  *
23  * WLAN Host Device Driver statistics related implementation
24  *
25  */
26 
27 #include "wlan_hdd_stats.h"
28 #include "sme_api.h"
29 #include "cds_sched.h"
30 #include "osif_sync.h"
31 #include "wlan_hdd_trace.h"
32 #include "wlan_hdd_lpass.h"
33 #include "hif.h"
34 #include <qca_vendor.h>
35 #include "wma_api.h"
36 #include "wlan_hdd_hostapd.h"
37 #include "wlan_osif_request_manager.h"
38 #include "wlan_hdd_debugfs_llstat.h"
39 #include "wlan_hdd_debugfs_mibstat.h"
40 #include "wlan_reg_services_api.h"
41 #include <wlan_cfg80211_mc_cp_stats.h>
42 #include "wlan_cp_stats_mc_ucfg_api.h"
43 #include "wlan_mlme_ucfg_api.h"
44 #include "wlan_mlme_ucfg_api.h"
45 #include "wlan_hdd_sta_info.h"
46 #include "cdp_txrx_misc.h"
47 #include "cdp_txrx_host_stats.h"
48 #include "wlan_hdd_object_manager.h"
49 #include "wlan_hdd_eht.h"
50 #include "wlan_dp_ucfg_api.h"
51 #include "wlan_cm_roam_ucfg_api.h"
52 #include <wlan_cp_stats_chipset_stats.h>
53 #include <wlan_cp_stats_ucfg_api.h>
54 #ifdef CNSS_GENL
55 #ifdef CONFIG_CNSS_OUT_OF_TREE
56 #include "cnss_nl.h"
57 #else
58 #include <net/cnss_nl.h>
59 #endif
60 #endif
61 #include "wlan_nan_api.h"
62 
63 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
64 #define HDD_INFO_SIGNAL                 STATION_INFO_SIGNAL
65 #define HDD_INFO_SIGNAL_AVG             STATION_INFO_SIGNAL_AVG
66 #define HDD_INFO_TX_PACKETS             STATION_INFO_TX_PACKETS
67 #define HDD_INFO_TX_RETRIES             STATION_INFO_TX_RETRIES
68 #define HDD_INFO_TX_FAILED              STATION_INFO_TX_FAILED
69 #define HDD_INFO_TX_BITRATE             STATION_INFO_TX_BITRATE
70 #define HDD_INFO_RX_BITRATE             STATION_INFO_RX_BITRATE
71 #define HDD_INFO_TX_BYTES               STATION_INFO_TX_BYTES
72 #define HDD_INFO_CHAIN_SIGNAL_AVG       STATION_INFO_CHAIN_SIGNAL_AVG
73 #define HDD_INFO_EXPECTED_THROUGHPUT    0
74 #define HDD_INFO_RX_BYTES               STATION_INFO_RX_BYTES
75 #define HDD_INFO_RX_PACKETS             STATION_INFO_RX_PACKETS
76 #define HDD_INFO_TX_BYTES64             0
77 #define HDD_INFO_RX_BYTES64             0
78 #define HDD_INFO_INACTIVE_TIME          0
79 #define HDD_INFO_CONNECTED_TIME         0
80 #define HDD_INFO_STA_FLAGS              0
81 #define HDD_INFO_RX_MPDUS               0
82 #define HDD_INFO_FCS_ERROR_COUNT        0
83 #else
84 #define HDD_INFO_SIGNAL                 BIT(NL80211_STA_INFO_SIGNAL)
85 #define HDD_INFO_SIGNAL_AVG             BIT(NL80211_STA_INFO_SIGNAL_AVG)
86 #define HDD_INFO_TX_PACKETS             BIT(NL80211_STA_INFO_TX_PACKETS)
87 #define HDD_INFO_TX_RETRIES             BIT(NL80211_STA_INFO_TX_RETRIES)
88 #define HDD_INFO_TX_FAILED              BIT(NL80211_STA_INFO_TX_FAILED)
89 #define HDD_INFO_TX_BITRATE             BIT(NL80211_STA_INFO_TX_BITRATE)
90 #define HDD_INFO_RX_BITRATE             BIT(NL80211_STA_INFO_RX_BITRATE)
91 #define HDD_INFO_TX_BYTES               BIT(NL80211_STA_INFO_TX_BYTES)
92 #define HDD_INFO_CHAIN_SIGNAL_AVG       BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
93 #define HDD_INFO_EXPECTED_THROUGHPUT  BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)
94 #define HDD_INFO_RX_BYTES               BIT(NL80211_STA_INFO_RX_BYTES)
95 #define HDD_INFO_RX_PACKETS             BIT(NL80211_STA_INFO_RX_PACKETS)
96 #define HDD_INFO_TX_BYTES64             BIT(NL80211_STA_INFO_TX_BYTES64)
97 #define HDD_INFO_RX_BYTES64             BIT(NL80211_STA_INFO_RX_BYTES64)
98 #define HDD_INFO_INACTIVE_TIME          BIT(NL80211_STA_INFO_INACTIVE_TIME)
99 #define HDD_INFO_CONNECTED_TIME         BIT(NL80211_STA_INFO_CONNECTED_TIME)
100 #define HDD_INFO_STA_FLAGS              BIT(NL80211_STA_INFO_STA_FLAGS)
101 #define HDD_INFO_RX_MPDUS             BIT_ULL(NL80211_STA_INFO_RX_MPDUS)
102 #define HDD_INFO_FCS_ERROR_COUNT      BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)
103 #endif /* kernel version less than 4.0.0 && no_backport */
104 
105 #define HDD_LINK_STATS_MAX		5
106 #define HDD_MAX_ALLOWED_LL_STATS_FAILURE	5
107 
108 #define INVALID_PREAMBLE 0xFF
109 
110 #define MAX_RSSI_MCS_INDEX 14
111 
112 #define MAX_HT_MCS_INDEX 7
113 
114 /* 11B, 11G Rate table include Basic rate and Extended rate
115  * The IDX field is the rate index
116  * The HI field is the rate when RSSI is strong or being ignored
117  *  (in this case we report actual rate)
118  * The MID field is the rate when RSSI is moderate
119  * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
120  * The LO field is the rate when RSSI is low
121  *  (in this case we don't report rates, actual current rate used)
122  */
123 static const struct index_data_rate_type supported_data_rate[] = {
124 	/* IDX     HI  HM  LM LO (RSSI-based index */
125 	{2,   { 10,  10, 10, 0} },
126 	{4,   { 20,  20, 10, 0} },
127 	{11,  { 55,  20, 10, 0} },
128 	{12,  { 60,  55, 20, 0} },
129 	{18,  { 90,  55, 20, 0} },
130 	{22,  {110,  55, 20, 0} },
131 	{24,  {120,  90, 60, 0} },
132 	{36,  {180, 120, 60, 0} },
133 	{44,  {220, 180, 60, 0} },
134 	{48,  {240, 180, 90, 0} },
135 	{66,  {330, 180, 90, 0} },
136 	{72,  {360, 240, 90, 0} },
137 	{96,  {480, 240, 120, 0} },
138 	{108, {540, 240, 120, 0} }
139 };
140 /* MCS Based rate table HT MCS parameters with Nss = 1 */
141 static const struct index_data_rate_type supported_mcs_rate_nss1[] = {
142 /* MCS  L20   L40   S20  S40 */
143 	{0, {65, 135, 72, 150} },
144 	{1, {130, 270, 144, 300} },
145 	{2, {195, 405, 217, 450} },
146 	{3, {260, 540, 289, 600} },
147 	{4, {390, 810, 433, 900} },
148 	{5, {520, 1080, 578, 1200} },
149 	{6, {585, 1215, 650, 1350} },
150 	{7, {650, 1350, 722, 1500} }
151 };
152 
153 /* HT MCS parameters with Nss = 2 */
154 static const struct index_data_rate_type supported_mcs_rate_nss2[] = {
155 /* MCS  L20    L40   S20   S40 */
156 	{0, {130, 270, 144, 300} },
157 	{1, {260, 540, 289, 600} },
158 	{2, {390, 810, 433, 900} },
159 	{3, {520, 1080, 578, 1200} },
160 	{4, {780, 1620, 867, 1800} },
161 	{5, {1040, 2160, 1156, 2400} },
162 	{6, {1170, 2430, 1300, 2700} },
163 	{7, {1300, 2700, 1444, 3000} }
164 };
165 
166 /* MCS Based VHT rate table MCS parameters with Nss = 1*/
167 static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
168 /* MCS  L80    S80     L40   S40    L20   S40*/
169 	{0, {293, 325}, {135, 150}, {65, 72} },
170 	{1, {585, 650}, {270, 300}, {130, 144} },
171 	{2, {878, 975}, {405, 450}, {195, 217} },
172 	{3, {1170, 1300}, {540, 600}, {260, 289} },
173 	{4, {1755, 1950}, {810, 900}, {390, 433} },
174 	{5, {2340, 2600}, {1080, 1200}, {520, 578} },
175 	{6, {2633, 2925}, {1215, 1350}, {585, 650} },
176 	{7, {2925, 3250}, {1350, 1500}, {650, 722} },
177 	{8, {3510, 3900}, {1620, 1800}, {780, 867} },
178 	{9, {3900, 4333}, {1800, 2000}, {780, 867} },
179 	{10, {4388, 4875}, {2025, 2250}, {975, 1083} },
180 	{11, {4875, 5417}, {2250, 2500}, {1083, 1203} }
181 };
182 
183 /*MCS parameters with Nss = 2*/
184 static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
185 /* MCS  L80    S80     L40   S40    L20   S40*/
186 	{0, {585, 650}, {270, 300}, {130, 144} },
187 	{1, {1170, 1300}, {540, 600}, {260, 289} },
188 	{2, {1755, 1950}, {810, 900}, {390, 433} },
189 	{3, {2340, 2600}, {1080, 1200}, {520, 578} },
190 	{4, {3510, 3900}, {1620, 1800}, {780, 867} },
191 	{5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
192 	{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
193 	{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
194 	{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
195 	{9, {7800, 8667}, {3600, 4000}, {1730, 1920} },
196 	{10, {8775, 9750}, {4050, 4500}, {1950, 2167} },
197 	{11, {9750, 10833}, {4500, 5000}, {2167, 2407} }
198 };
199 
200 /*array index points to MCS and array value points respective rssi*/
201 static int rssi_mcs_tbl[][MAX_RSSI_MCS_INDEX] = {
202 /*  MCS 0   1    2   3    4    5    6    7    8    9    10   11   12   13*/
203 	/* 20 */
204 	{-82, -79, -77, -74, -70, -66, -65, -64, -59, -57, -52, -48, -46, -42},
205 	/* 40 */
206 	{-79, -76, -74, -71, -67, -63, -62, -61, -56, -54, -49, -45, -43, -39},
207 	/* 80 */
208 	{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42, -46, -36}
209 };
210 
211 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)212 static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)
213 {
214 	if (he_mcs_12_13_map)
215 		return true;
216 	else
217 		return false;
218 }
219 #else
wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)220 static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)
221 {
222 	return false;
223 }
224 #endif
225 
226 static bool get_station_fw_request_needed = true;
227 
228 /*
229  * copy_station_stats_to_adapter() - Copy station stats to adapter
230  * @link_info: Pointer to link_info in adapter
231  * @stats: Pointer to the station stats event
232  *
233  * Return: 0 if success, non-zero for failure
234  */
copy_station_stats_to_adapter(struct wlan_hdd_link_info * link_info,struct stats_event * stats)235 static int copy_station_stats_to_adapter(struct wlan_hdd_link_info *link_info,
236 					 struct stats_event *stats)
237 {
238 	int ret = 0;
239 	struct wlan_mlme_nss_chains *dynamic_cfg;
240 	uint32_t tx_nss, rx_nss;
241 	struct wlan_objmgr_vdev *vdev;
242 	uint16_t he_mcs_12_13_map;
243 	bool is_he_mcs_12_13_supported;
244 	struct hdd_stats *hdd_stats;
245 	struct hdd_adapter *adapter = link_info->adapter;
246 
247 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
248 	if (!vdev)
249 		return -EINVAL;
250 
251 	hdd_stats = &link_info->hdd_stats;
252 	/* save summary stats to legacy location */
253 	qdf_mem_copy(hdd_stats->summary_stat.retry_cnt,
254 		     stats->vdev_summary_stats[0].stats.retry_cnt,
255 		     sizeof(hdd_stats->summary_stat.retry_cnt));
256 	qdf_mem_copy(hdd_stats->summary_stat.multiple_retry_cnt,
257 		     stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
258 		     sizeof(hdd_stats->summary_stat.multiple_retry_cnt));
259 	qdf_mem_copy(hdd_stats->summary_stat.tx_frm_cnt,
260 		     stats->vdev_summary_stats[0].stats.tx_frm_cnt,
261 		     sizeof(hdd_stats->summary_stat.tx_frm_cnt));
262 	qdf_mem_copy(hdd_stats->summary_stat.fail_cnt,
263 		     stats->vdev_summary_stats[0].stats.fail_cnt,
264 		     sizeof(hdd_stats->summary_stat.fail_cnt));
265 	hdd_stats->summary_stat.snr = stats->vdev_summary_stats[0].stats.snr;
266 	hdd_stats->summary_stat.rssi = stats->vdev_summary_stats[0].stats.rssi;
267 	hdd_stats->summary_stat.rx_frm_cnt =
268 			stats->vdev_summary_stats[0].stats.rx_frm_cnt;
269 	hdd_stats->summary_stat.frm_dup_cnt =
270 			stats->vdev_summary_stats[0].stats.frm_dup_cnt;
271 	hdd_stats->summary_stat.rts_fail_cnt =
272 			stats->vdev_summary_stats[0].stats.rts_fail_cnt;
273 	hdd_stats->summary_stat.ack_fail_cnt =
274 			stats->vdev_summary_stats[0].stats.ack_fail_cnt;
275 	hdd_stats->summary_stat.rts_succ_cnt =
276 			stats->vdev_summary_stats[0].stats.rts_succ_cnt;
277 	hdd_stats->summary_stat.rx_discard_cnt =
278 			stats->vdev_summary_stats[0].stats.rx_discard_cnt;
279 	hdd_stats->summary_stat.rx_error_cnt =
280 			stats->vdev_summary_stats[0].stats.rx_error_cnt;
281 	hdd_stats->peer_stats.rx_count = stats->peer_adv_stats->rx_count;
282 	hdd_stats->peer_stats.rx_bytes = stats->peer_adv_stats->rx_bytes;
283 	hdd_stats->peer_stats.fcs_count = stats->peer_adv_stats->fcs_count;
284 	adapter->tx_power.tx_pwr = stats->pdev_stats->max_pwr;
285 	adapter->tx_power.tx_pwr_cached_timestamp =
286 			qdf_system_ticks_to_msecs(qdf_system_ticks());
287 	/* Copy vdev status info sent by FW */
288 	if (stats->vdev_extd_stats)
289 		link_info->is_mlo_vdev_active =
290 			stats->vdev_extd_stats[0].is_mlo_vdev_active;
291 
292 	dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
293 	if (!dynamic_cfg) {
294 		hdd_err("nss chain dynamic config NULL");
295 		ret = -EINVAL;
296 		goto out;
297 	}
298 
299 	switch (hdd_conn_get_connected_band(link_info)) {
300 	case BAND_2G:
301 		tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
302 		rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
303 		break;
304 	case BAND_5G:
305 		tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
306 		rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
307 		break;
308 	default:
309 		tx_nss = wlan_vdev_mlme_get_nss(vdev);
310 		rx_nss = wlan_vdev_mlme_get_nss(vdev);
311 	}
312 
313 	/* Intersection of self and AP's NSS capability */
314 	if (tx_nss > wlan_vdev_mlme_get_nss(vdev))
315 		tx_nss = wlan_vdev_mlme_get_nss(vdev);
316 
317 	if (rx_nss > wlan_vdev_mlme_get_nss(vdev))
318 		rx_nss = wlan_vdev_mlme_get_nss(vdev);
319 
320 	/* save class a stats to legacy location */
321 	hdd_stats->class_a_stat.tx_nss = tx_nss;
322 	hdd_stats->class_a_stat.rx_nss = rx_nss;
323 	hdd_stats->class_a_stat.tx_rate = stats->tx_rate;
324 	hdd_stats->class_a_stat.rx_rate = stats->rx_rate;
325 	hdd_stats->class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
326 
327 	he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev);
328 	is_he_mcs_12_13_supported =
329 			wlan_hdd_is_he_mcs_12_13_supported(he_mcs_12_13_map);
330 	hdd_stats->class_a_stat.tx_mcs_index =
331 		sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
332 				is_he_mcs_12_13_supported,
333 				&hdd_stats->class_a_stat.tx_nss,
334 				&hdd_stats->class_a_stat.tx_dcm,
335 				&hdd_stats->class_a_stat.tx_gi,
336 				&hdd_stats->class_a_stat.tx_mcs_rate_flags);
337 	hdd_stats->class_a_stat.rx_mcs_index =
338 		sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
339 				is_he_mcs_12_13_supported,
340 				&hdd_stats->class_a_stat.rx_nss,
341 				&hdd_stats->class_a_stat.rx_dcm,
342 				&hdd_stats->class_a_stat.rx_gi,
343 				&hdd_stats->class_a_stat.rx_mcs_rate_flags);
344 
345 	/* save per chain rssi to legacy location */
346 	qdf_mem_copy(hdd_stats->per_chain_rssi_stats.rssi,
347 		     stats->vdev_chain_rssi[0].chain_rssi,
348 		     sizeof(stats->vdev_chain_rssi[0].chain_rssi));
349 	hdd_stats->bcn_protect_stats = stats->bcn_protect_stats;
350 out:
351 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
352 	return ret;
353 }
354 
355 #ifdef WLAN_FEATURE_BIG_DATA_STATS
356 /*
357  * copy_station_big_data_stats_to_adapter() - Copy big data stats to adapter
358  * @link_info: Link info pointer in HDD adapter.
359  * @stats: Pointer to the big data stats event
360  *
361  * Return: 0 if success, non-zero for failure
362  */
363 static void
copy_station_big_data_stats_to_adapter(struct wlan_hdd_link_info * link_info,struct big_data_stats_event * stats)364 copy_station_big_data_stats_to_adapter(struct wlan_hdd_link_info *link_info,
365 				       struct big_data_stats_event *stats)
366 {
367 	struct big_data_stats_event *big_data_stats =
368 						&link_info->big_data_stats;
369 
370 	big_data_stats->vdev_id = stats->vdev_id;
371 	big_data_stats->tsf_out_of_sync = stats->tsf_out_of_sync;
372 	big_data_stats->ani_level = stats->ani_level;
373 	big_data_stats->last_data_tx_pwr = stats->last_data_tx_pwr;
374 	big_data_stats->target_power_dsss = stats->target_power_dsss;
375 	big_data_stats->target_power_ofdm = stats->target_power_ofdm;
376 	big_data_stats->last_tx_data_rix = stats->last_tx_data_rix;
377 	big_data_stats->last_tx_data_rate_kbps = stats->last_tx_data_rate_kbps;
378 }
379 #endif
380 
381 #ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
382 static void
hdd_update_station_stats_cached_timestamp(struct hdd_adapter * adapter)383 hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
384 {
385 	adapter->sta_stats_cached_timestamp =
386 				qdf_system_ticks_to_msecs(qdf_system_ticks());
387 }
388 #else
389 static void
hdd_update_station_stats_cached_timestamp(struct hdd_adapter * adapter)390 hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
391 {
392 }
393 #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
394 
395 #ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI
396 /**
397  * wlan_hdd_qmi_get_sync_resume() - Get operation to trigger RTPM
398  * sync resume without WoW exit
399  *
400  * call qmi_get before sending qmi, and do qmi_put after all the
401  * qmi response rececived from fw. so this request wlan host to
402  * wait for the last qmi response, if it doesn't wait, qmi put
403  * which cause MHI enter M3(suspend) before all the qmi response,
404  * and MHI will trigger a RTPM resume, this violated design of by
405  * sending cmd by qmi without wow resume.
406  *
407  * Returns: 0 for success, non-zero for failure
408  */
wlan_hdd_qmi_get_sync_resume(void)409 int wlan_hdd_qmi_get_sync_resume(void)
410 {
411 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
412 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
413 
414 	if (wlan_hdd_validate_context(hdd_ctx))
415 		return -EINVAL;
416 
417 	if (!hdd_ctx->config->is_qmi_stats_enabled) {
418 		hdd_debug("periodic stats over qmi is disabled");
419 		return 0;
420 	}
421 
422 	if (!qdf_ctx) {
423 		hdd_err("qdf_ctx is null");
424 		return -EINVAL;
425 	}
426 
427 	return pld_qmi_send_get(qdf_ctx->dev);
428 }
429 
430 /**
431  * wlan_hdd_qmi_put_suspend() - Put operation to trigger RTPM suspend
432  * without WoW entry
433  *
434  * Returns: 0 for success, non-zero for failure
435  */
wlan_hdd_qmi_put_suspend(void)436 int wlan_hdd_qmi_put_suspend(void)
437 {
438 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
439 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
440 
441 	if (wlan_hdd_validate_context(hdd_ctx))
442 		return -EINVAL;
443 
444 	if (!hdd_ctx->config->is_qmi_stats_enabled) {
445 		hdd_debug("periodic stats over qmi is disabled");
446 		return 0;
447 	}
448 
449 	if (!qdf_ctx) {
450 		hdd_err("qdf_ctx is null");
451 		return -EINVAL;
452 	}
453 
454 	return pld_qmi_send_put(qdf_ctx->dev);
455 }
456 #else
wlan_hdd_qmi_get_sync_resume(void)457 int wlan_hdd_qmi_get_sync_resume(void)
458 {
459 	return 0;
460 }
461 
wlan_hdd_qmi_put_suspend(void)462 int wlan_hdd_qmi_put_suspend(void)
463 {
464 	return 0;
465 }
466 #endif /* end if of WLAN_FEATURE_WMI_SEND_RECV_QMI */
467 
468 /*
469  * wlan_hdd_is_mlo_connection() - Check if connection is legacy or mlo
470  * @link_info: Link info pointer in HDD adapter
471  *
472  * Return: True if MLO connection, else False
473  */
wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info * link_info)474 static bool wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info *link_info)
475 {
476 	struct wlan_objmgr_vdev *vdev;
477 	bool ret = false;
478 
479 	if (!link_info) {
480 		hdd_err("Invalid link_info");
481 		return ret;
482 	}
483 
484 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
485 	if (!vdev) {
486 		hdd_err("invalid vdev");
487 		return ret;
488 	}
489 
490 	if (wlan_vdev_mlme_is_mlo_vdev(vdev))
491 		ret = true;
492 
493 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
494 	return ret;
495 }
496 
497 static struct wlan_hdd_link_info *
hdd_get_link_info_by_bssid(struct hdd_context * hdd_ctx,const uint8_t * bssid)498 hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid)
499 {
500 	struct hdd_adapter *adapter, *next_adapter = NULL;
501 	struct hdd_station_ctx *sta_ctx;
502 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_BSSID;
503 	struct wlan_hdd_link_info *link_info;
504 
505 	if (qdf_is_macaddr_zero((struct qdf_mac_addr *)bssid))
506 		return NULL;
507 
508 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
509 					   dbgid) {
510 		hdd_adapter_for_each_link_info(adapter, link_info) {
511 			sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
512 			if (qdf_is_macaddr_equal((struct qdf_mac_addr *)bssid,
513 						 &sta_ctx->conn_info.bssid)) {
514 				hdd_adapter_dev_put_debug(adapter, dbgid);
515 				if (next_adapter)
516 					hdd_adapter_dev_put_debug(next_adapter,
517 								  dbgid);
518 				return link_info;
519 			}
520 		}
521 		hdd_adapter_dev_put_debug(adapter, dbgid);
522 	}
523 	return NULL;
524 }
525 
526 #define WLAN_INVALID_RSSI_VALUE -128
527 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
528 /**
529  * wlan_hdd_is_per_link_stats_supported - Check if FW supports per link stats
530  * @hdd_ctx: Pointer to hdd context
531  *
532  * Return: true if FW supports, else False
533  */
534 static bool
wlan_hdd_is_per_link_stats_supported(struct hdd_context * hdd_ctx)535 wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
536 {
537 	if (hdd_ctx->is_mlo_per_link_stats_supported)
538 		return true;
539 
540 	hdd_debug("mlo per link stats is not supported by FW");
541 	return false;
542 }
543 
544 /**
545  * wlan_hdd_get_bss_peer_mld_mac() - get bss peer mld mac address
546  * @link_info: Link info pointer in HDD adapter
547  * @mld_mac: pointer to mld mac address
548  *
549  * Return: QDF_STATUS
550  */
551 static QDF_STATUS
wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info * link_info,struct qdf_mac_addr * mld_mac)552 wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
553 			      struct qdf_mac_addr *mld_mac)
554 {
555 	struct wlan_objmgr_vdev *vdev;
556 	QDF_STATUS status;
557 
558 	vdev = hdd_objmgr_get_vdev_by_user(link_info,
559 					   WLAN_OSIF_STATS_ID);
560 	if (!vdev)
561 		return QDF_STATUS_E_INVAL;
562 
563 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
564 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
565 		return QDF_STATUS_E_INVAL;
566 	}
567 
568 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, mld_mac);
569 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
570 	return status;
571 }
572 
573 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
574 static bool
wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info * link_info)575 wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
576 {
577 	struct wlan_objmgr_vdev *vdev;
578 	bool ret = false;
579 
580 	if (!link_info) {
581 		hdd_err_rl("Invalid link info");
582 		return ret;
583 	}
584 
585 	if (!wlan_hdd_is_mlo_connection(link_info))
586 		return ret;
587 
588 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
589 	if (!vdev) {
590 		hdd_err("invalid vdev");
591 		return ret;
592 	}
593 
594 	ret = mlo_mgr_is_link_switch_in_progress(vdev);
595 
596 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
597 	return ret;
598 }
599 #else
600 static inline bool
wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info * link_info)601 wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
602 {
603 	return false;
604 }
605 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
606 
607 /**
608  * wlan_hdd_copy_sinfo_to_link_info() - Copy sinfo to link_info
609  * @link_info: Pointer to the hdd link info
610  * @sinfo: Pointer to kernel station info struct
611  *
612  * Return: none
613  */
614 static void
wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)615 wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
616 				 struct station_info *sinfo)
617 {
618 	struct wlan_hdd_station_stats_info *hdd_sinfo;
619 	struct hdd_station_ctx *sta_ctx;
620 	uint8_t i, *link_mac;
621 
622 	if (!wlan_hdd_is_mlo_connection(link_info))
623 		return;
624 
625 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
626 
627 	hdd_sinfo = &link_info->hdd_sinfo;
628 
629 	hdd_sinfo->signal = sinfo->signal;
630 	hdd_sinfo->signal_avg = sinfo->signal_avg;
631 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
632 		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
633 
634 	qdf_mem_copy(&hdd_sinfo->txrate,
635 		     &sinfo->txrate, sizeof(sinfo->txrate));
636 
637 	qdf_mem_copy(&hdd_sinfo->rxrate,
638 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
639 	hdd_sinfo->rx_bytes = sinfo->rx_bytes;
640 	hdd_sinfo->tx_bytes = sinfo->tx_bytes;
641 	hdd_sinfo->rx_packets = sinfo->rx_packets;
642 	hdd_sinfo->tx_packets = sinfo->tx_packets;
643 	hdd_sinfo->tx_retries = sinfo->tx_retries;
644 	hdd_sinfo->tx_failed = sinfo->tx_failed;
645 	hdd_sinfo->rx_mpdu_count = sinfo->rx_mpdu_count;
646 	hdd_sinfo->fcs_err_count = sinfo->fcs_err_count;
647 
648 	link_mac = sta_ctx->conn_info.bssid.bytes;
649 	hdd_nofl_debug("copied sinfo for " QDF_MAC_ADDR_FMT " into link_info",
650 		       QDF_MAC_ADDR_REF(link_mac));
651 }
652 
653 /**
654  * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo
655  * @sinfo: Pointer to kernel station info struct
656  * @hdd_sinfo: Pointer to the hdd station stats info struct
657  *
658  * Return: none
659  */
660 static void
wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info * sinfo,struct wlan_hdd_station_stats_info * hdd_sinfo)661 wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo,
662 				 struct wlan_hdd_station_stats_info *hdd_sinfo)
663 {
664 	uint8_t i;
665 
666 	sinfo->signal = hdd_sinfo->signal;
667 	sinfo->signal_avg = hdd_sinfo->signal_avg;
668 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
669 		sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i];
670 
671 	if (!hdd_sinfo->signal) {
672 		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
673 		sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
674 		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
675 			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
676 	}
677 
678 	qdf_mem_copy(&sinfo->txrate,
679 		     &hdd_sinfo->txrate, sizeof(sinfo->txrate));
680 
681 	qdf_mem_copy(&sinfo->rxrate,
682 		     &hdd_sinfo->rxrate, sizeof(sinfo->rxrate));
683 	sinfo->rx_bytes = hdd_sinfo->rx_bytes;
684 	sinfo->tx_bytes = hdd_sinfo->tx_bytes;
685 	sinfo->rx_packets = hdd_sinfo->rx_packets;
686 	sinfo->tx_packets = hdd_sinfo->tx_packets;
687 	sinfo->tx_retries = hdd_sinfo->tx_retries;
688 	sinfo->tx_failed = hdd_sinfo->tx_failed;
689 	sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count;
690 	sinfo->fcs_err_count = hdd_sinfo->fcs_err_count;
691 }
692 
693 /**
694  * wlan_hdd_update_sinfo() - Function to update station info structure
695  * @sinfo: kernel station_info to populate
696  * @link_info: Pointer to the hdd link info
697  *
698  * Return: None
699  */
wlan_hdd_update_sinfo(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)700 static void wlan_hdd_update_sinfo(struct station_info *sinfo,
701 				  struct wlan_hdd_link_info *link_info)
702 {
703 	uint8_t i;
704 
705 	if (!link_info) {
706 		hdd_err("Invalid link_info");
707 		return;
708 	}
709 
710 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &link_info->hdd_sinfo);
711 
712 	if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
713 		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
714 		sinfo->signal_avg = WLAN_INVALID_RSSI_VALUE;
715 		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
716 			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
717 	}
718 
719 	sinfo->filled |= HDD_INFO_SIGNAL | HDD_INFO_SIGNAL_AVG |
720 			HDD_INFO_CHAIN_SIGNAL_AVG | HDD_INFO_TX_PACKETS |
721 			HDD_INFO_TX_RETRIES | HDD_INFO_TX_FAILED |
722 			HDD_INFO_TX_BITRATE | HDD_INFO_RX_BITRATE |
723 			HDD_INFO_TX_BYTES | HDD_INFO_RX_BYTES |
724 			HDD_INFO_RX_PACKETS | HDD_INFO_FCS_ERROR_COUNT |
725 			HDD_INFO_RX_MPDUS;
726 }
727 
728 static void
wlan_hdd_get_mlo_links_count(struct hdd_adapter * adapter,uint32_t * count)729 wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count)
730 {
731 	struct wlan_hdd_link_info *link_info;
732 	struct hdd_station_ctx *sta_ctx = NULL;
733 	u32 num_links = 0;
734 
735 	hdd_adapter_for_each_link_info(adapter, link_info) {
736 		if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE ||
737 		    link_info->adapter->device_mode == QDF_STA_MODE) {
738 			sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
739 			if (sta_ctx->conn_info.ieee_link_id !=
740 			    WLAN_INVALID_LINK_ID) {
741 				num_links++;
742 			}
743 		} else if (link_info->adapter->device_mode == QDF_SAP_MODE ||
744 			   link_info->adapter->device_mode == QDF_P2P_GO_MODE) {
745 			if (test_bit(SOFTAP_BSS_STARTED,
746 				     &link_info->link_flags)) {
747 				num_links++;
748 			}
749 		}
750 	}
751 
752 	*count = num_links;
753 }
754 
755 #else
756 static inline bool
wlan_hdd_is_per_link_stats_supported(struct hdd_context * hdd_ctx)757 wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
758 {
759 	return false;
760 }
761 
762 static inline QDF_STATUS
wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info * link_info,struct qdf_mac_addr * mld_mac)763 wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
764 			      struct qdf_mac_addr *mld_mac)
765 {
766 	return QDF_STATUS_E_FAILURE;
767 }
768 
769 static inline bool
wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info * link_info)770 wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
771 {
772 	return false;
773 }
774 
775 static inline void
wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)776 wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
777 				 struct station_info *sinfo)
778 {
779 }
780 
781 static inline void
wlan_hdd_update_sinfo(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)782 wlan_hdd_update_sinfo(struct station_info *sinfo,
783 		      struct wlan_hdd_link_info *link_info)
784 {
785 }
786 
787 static inline void
wlan_hdd_get_mlo_links_count(struct hdd_adapter * adapter,uint32_t * count)788 wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count)
789 {
790 }
791 #endif
792 
793 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
794 
795 /**
796  * struct hdd_ll_stats - buffered hdd link layer stats
797  * @ll_stats_node: pointer to next stats buffered in scheduler thread context
798  * @result_param_id: Received link layer stats ID
799  * @result: received stats from FW
800  * @more_data: if more stats are pending
801  * @stats_nradio_npeer: union of counts
802  * @stats_nradio_npeer.no_of_radios: no of radios
803  * @stats_nradio_npeer.no_of_peers: no of peers
804  */
805 struct hdd_ll_stats {
806 	qdf_list_node_t ll_stats_node;
807 	u32 result_param_id;
808 	void *result;
809 	u32 more_data;
810 	union {
811 		u32 no_of_radios;
812 		u32 no_of_peers;
813 	} stats_nradio_npeer;
814 };
815 
816 /**
817  * struct hdd_ll_stats_priv - hdd link layer stats private
818  * @ll_stats_q: head to different link layer stats received in scheduler
819  *            thread context
820  * @request_id: userspace-assigned link layer stats request id
821  * @request_bitmap: userspace-assigned link layer stats request bitmap
822  * @ll_stats_lock: Lock to serially access request_bitmap
823  * @vdev_id: id of vdev handle
824  * @is_mlo_req: is the request for mlo link layer stats
825  * @mlo_vdev_id_bitmap: bitmap of all ml vdevs
826  */
827 struct hdd_ll_stats_priv {
828 	qdf_list_t ll_stats_q;
829 	uint32_t request_id;
830 	uint32_t request_bitmap;
831 	qdf_spinlock_t ll_stats_lock;
832 	uint8_t vdev_id;
833 	bool is_mlo_req;
834 	uint32_t mlo_vdev_id_bitmap;
835 };
836 
837 /*
838  * Used to allocate the size of 4096 for the link layer stats.
839  * The size of 4096 is considered assuming that all data per
840  * respective event fit with in the limit.Please take a call
841  * on the limit based on the data requirements on link layer
842  * statistics.
843  */
844 #define LL_STATS_EVENT_BUF_SIZE 4096
845 
846 /**
847  * put_wifi_rate_stat() - put wifi rate stats
848  * @stats: Pointer to stats context
849  * @vendor_event: Pointer to vendor event
850  *
851  * Return: bool
852  */
put_wifi_rate_stat(struct wifi_rate_stat * stats,struct sk_buff * vendor_event)853 static bool put_wifi_rate_stat(struct wifi_rate_stat *stats,
854 			       struct sk_buff *vendor_event)
855 {
856 	if (nla_put_u8(vendor_event,
857 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
858 		       stats->rate.preamble) ||
859 	    nla_put_u8(vendor_event,
860 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
861 		       stats->rate.nss) ||
862 	    nla_put_u8(vendor_event,
863 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
864 		       stats->rate.bw) ||
865 	    nla_put_u8(vendor_event,
866 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
867 		       stats->rate.rate_or_mcs_index) ||
868 	    nla_put_u32(vendor_event,
869 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
870 			stats->rate.bitrate) ||
871 	    nla_put_u32(vendor_event,
872 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
873 			stats->tx_mpdu) ||
874 	    nla_put_u32(vendor_event,
875 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
876 			stats->rx_mpdu) ||
877 	    nla_put_u32(vendor_event,
878 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
879 			stats->mpdu_lost) ||
880 	    nla_put_u32(vendor_event,
881 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
882 			stats->retries) ||
883 	    nla_put_u32(vendor_event,
884 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
885 			stats->retries_short) ||
886 	    nla_put_u32(vendor_event,
887 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
888 			stats->retries_long)) {
889 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
890 		return false;
891 	}
892 
893 	return true;
894 }
895 
896 /**
897  * put_wifi_peer_rates() - put wifi peer rate info
898  * @stats: Pointer to stats context
899  * @vendor_event: Pointer to vendor event
900  *
901  * Return: bool
902  */
put_wifi_peer_rates(struct wifi_peer_info * stats,struct sk_buff * vendor_event)903 static bool put_wifi_peer_rates(struct wifi_peer_info *stats,
904 				struct sk_buff *vendor_event)
905 {
906 	uint32_t i;
907 	struct wifi_rate_stat *rate_stat;
908 	int nest_id;
909 	struct nlattr *info;
910 	struct nlattr *rates;
911 
912 	/* no rates is ok */
913 	if (!stats->num_rate)
914 		return true;
915 
916 	nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
917 	info = nla_nest_start(vendor_event, nest_id);
918 	if (!info)
919 		return false;
920 
921 	for (i = 0; i < stats->num_rate; i++) {
922 		rates = nla_nest_start(vendor_event, i);
923 		if (!rates)
924 			return false;
925 		rate_stat = &stats->rate_stats[i];
926 		if (!put_wifi_rate_stat(rate_stat, vendor_event)) {
927 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
928 			return false;
929 		}
930 		nla_nest_end(vendor_event, rates);
931 	}
932 	nla_nest_end(vendor_event, info);
933 
934 	return true;
935 }
936 
937 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
938 /**
939  * wlan_hdd_put_mlo_link_iface_info() - Send per mlo link info to framework
940  * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct
941  * @skb: Pointer to data buffer
942  *
943  * Return: True on success, False on failure
944  */
945 static bool
wlan_hdd_put_mlo_link_iface_info(struct wlan_hdd_mlo_iface_stats_info * info,struct sk_buff * skb)946 wlan_hdd_put_mlo_link_iface_info(struct wlan_hdd_mlo_iface_stats_info *info,
947 				 struct sk_buff *skb)
948 {
949 	if (nla_put_u8(skb,
950 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
951 		       info->link_id) ||
952 	    nla_put_u32(skb,
953 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
954 			info->radio_id) ||
955 	    nla_put_u32(skb,
956 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
957 			info->freq)) {
958 		hdd_err("wlan_hdd_put_mlo_link_iface_info failed");
959 		return false;
960 	}
961 
962 	return true;
963 }
964 
965 /**
966  * wlan_hdd_get_connected_link_info() - Get connected links' id and frequency
967  * @link_info: Link info pointerin adapter
968  * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct
969  *
970  * Return: void
971  */
972 static void
wlan_hdd_get_connected_link_info(struct wlan_hdd_link_info * link_info,struct wlan_hdd_mlo_iface_stats_info * info)973 wlan_hdd_get_connected_link_info(struct wlan_hdd_link_info *link_info,
974 				 struct wlan_hdd_mlo_iface_stats_info *info)
975 {
976 	struct hdd_station_ctx *sta_ctx = NULL;
977 	struct hdd_ap_ctx *ap_ctx = NULL;
978 
979 	info->link_id = WLAN_INVALID_LINK_ID;
980 
981 	if (!link_info) {
982 		hdd_err("Invalid link_info");
983 		return;
984 	}
985 
986 	if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE ||
987 	    link_info->adapter->device_mode == QDF_STA_MODE) {
988 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
989 		info->link_id = sta_ctx->conn_info.ieee_link_id;
990 		info->freq = sta_ctx->conn_info.chan_freq;
991 	} else if ((link_info->adapter->device_mode == QDF_SAP_MODE ||
992 		    link_info->adapter->device_mode == QDF_P2P_GO_MODE) &&
993 		   test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
994 		ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
995 		info->link_id = ap_ctx->sap_config.link_id;
996 		info->freq = ap_ctx->sap_config.chan_freq;
997 	}
998 }
999 #endif
1000 
1001 /**
1002  * put_wifi_peer_info() - put wifi peer info
1003  * @stats: Pointer to stats context
1004  * @vendor_event: Pointer to vendor event
1005  *
1006  * Return: bool
1007  */
put_wifi_peer_info(struct wifi_peer_info * stats,struct sk_buff * vendor_event)1008 static bool put_wifi_peer_info(struct wifi_peer_info *stats,
1009 			       struct sk_buff *vendor_event)
1010 {
1011 	if (nla_put_u32(vendor_event,
1012 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
1013 			wmi_to_sir_peer_type(stats->type)) ||
1014 	    nla_put(vendor_event,
1015 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
1016 		       QDF_MAC_ADDR_SIZE, &stats->peer_macaddr.bytes[0]) ||
1017 	    nla_put_u32(vendor_event,
1018 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
1019 			stats->capabilities) ||
1020 	    nla_put_u32(vendor_event,
1021 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
1022 			stats->num_rate)) {
1023 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1024 		return false;
1025 	}
1026 
1027 	return put_wifi_peer_rates(stats, vendor_event);
1028 }
1029 
1030 /**
1031  * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
1032  * @stats: Pointer to stats context
1033  * @vendor_event: Pointer to vendor event
1034  *
1035  * Return: bool
1036  */
put_wifi_wmm_ac_stat(wmi_wmm_ac_stats * stats,struct sk_buff * vendor_event)1037 static bool put_wifi_wmm_ac_stat(wmi_wmm_ac_stats *stats,
1038 				 struct sk_buff *vendor_event)
1039 {
1040 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
1041 			stats->ac_type) ||
1042 	    nla_put_u32(vendor_event,
1043 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
1044 			stats->tx_mpdu) ||
1045 	    nla_put_u32(vendor_event,
1046 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
1047 			stats->rx_mpdu) ||
1048 	    nla_put_u32(vendor_event,
1049 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
1050 			stats->tx_mcast) ||
1051 	    nla_put_u32(vendor_event,
1052 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
1053 			stats->rx_mcast) ||
1054 	    nla_put_u32(vendor_event,
1055 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
1056 			stats->rx_ampdu) ||
1057 	    nla_put_u32(vendor_event,
1058 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
1059 			stats->tx_ampdu) ||
1060 	    nla_put_u32(vendor_event,
1061 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
1062 			stats->mpdu_lost) ||
1063 	    nla_put_u32(vendor_event,
1064 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
1065 			stats->retries) ||
1066 	    nla_put_u32(vendor_event,
1067 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
1068 			stats->retries_short) ||
1069 	    nla_put_u32(vendor_event,
1070 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
1071 			stats->retries_long) ||
1072 	    nla_put_u32(vendor_event,
1073 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
1074 			stats->contention_time_min) ||
1075 	    nla_put_u32(vendor_event,
1076 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
1077 			stats->contention_time_max) ||
1078 	    nla_put_u32(vendor_event,
1079 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
1080 			stats->contention_time_avg) ||
1081 	    nla_put_u32(vendor_event,
1082 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
1083 			stats->contention_num_samples)) {
1084 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1085 		return false;
1086 	}
1087 
1088 	return true;
1089 }
1090 
1091 /**
1092  * put_wifi_interface_info() - put wifi interface info
1093  * @stats: Pointer to stats context
1094  * @vendor_event: Pointer to vendor event
1095  * @link_info: Pointer to link_info
1096  *
1097  * Return: bool
1098  */
put_wifi_interface_info(struct wifi_interface_info * stats,struct sk_buff * vendor_event,struct wlan_hdd_link_info * link_info)1099 static bool put_wifi_interface_info(struct wifi_interface_info *stats,
1100 				    struct sk_buff *vendor_event,
1101 				    struct wlan_hdd_link_info *link_info)
1102 {
1103 	if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE ||
1104 	    link_info->adapter->device_mode == QDF_STA_MODE) {
1105 		if (nla_put_u32(vendor_event,
1106 				QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
1107 				stats->state)) {
1108 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1109 			return false;
1110 		}
1111 	}
1112 
1113 	if (nla_put_u32(vendor_event,
1114 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
1115 			stats->mode) ||
1116 	    nla_put(vendor_event,
1117 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
1118 		    QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
1119 	    nla_put_u32(vendor_event,
1120 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
1121 			stats->roaming) ||
1122 	    nla_put_u32(vendor_event,
1123 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
1124 			stats->capabilities) ||
1125 	    nla_put(vendor_event,
1126 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
1127 		    strlen(stats->ssid), stats->ssid) ||
1128 	    nla_put(vendor_event,
1129 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
1130 		    QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
1131 	    nla_put(vendor_event,
1132 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
1133 		    REG_ALPHA2_LEN + 1, stats->apCountryStr) ||
1134 	    nla_put(vendor_event,
1135 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
1136 		    REG_ALPHA2_LEN + 1, stats->countryStr) ||
1137 	    nla_put_u8(vendor_event,
1138 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE,
1139 		       stats->time_slice_duty_cycle)) {
1140 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1141 		return false;
1142 	}
1143 
1144 	return true;
1145 }
1146 
1147 /**
1148  * put_wifi_iface_stats() - put wifi interface stats
1149  * @if_stat: Pointer to interface stats context
1150  * @num_peers: Number of peers
1151  * @vendor_event: Pointer to vendor event
1152  * @link_info: Pointer to link_info
1153  *
1154  * Return: bool
1155  */
put_wifi_iface_stats(struct wifi_interface_stats * if_stat,u32 num_peers,struct sk_buff * vendor_event,struct wlan_hdd_link_info * link_info)1156 static bool put_wifi_iface_stats(struct wifi_interface_stats *if_stat,
1157 				 u32 num_peers, struct sk_buff *vendor_event,
1158 				 struct wlan_hdd_link_info *link_info)
1159 {
1160 	int i = 0;
1161 	struct nlattr *wmm_info;
1162 	struct nlattr *wmm_stats;
1163 	u64 average_tsf_offset;
1164 	wmi_iface_link_stats *link_stats = &if_stat->link_stats;
1165 
1166 	if (!put_wifi_interface_info(&if_stat->info, vendor_event, link_info)) {
1167 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1168 		return false;
1169 
1170 	}
1171 
1172 	average_tsf_offset =  link_stats->avg_bcn_spread_offset_high;
1173 	average_tsf_offset =  (average_tsf_offset << 32) |
1174 		link_stats->avg_bcn_spread_offset_low;
1175 
1176 	if (nla_put_u32(vendor_event,
1177 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1178 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE) ||
1179 	    nla_put_u32(vendor_event,
1180 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
1181 			num_peers) ||
1182 	    nla_put_u32(vendor_event,
1183 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
1184 			link_stats->beacon_rx) ||
1185 	    nla_put_u32(vendor_event,
1186 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
1187 			link_stats->mgmt_rx) ||
1188 	    nla_put_u32(vendor_event,
1189 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
1190 			link_stats->mgmt_action_rx) ||
1191 	    nla_put_u32(vendor_event,
1192 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
1193 			link_stats->mgmt_action_tx) ||
1194 	    nla_put_u32(vendor_event,
1195 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
1196 			link_stats->rssi_mgmt) ||
1197 	    nla_put_u32(vendor_event,
1198 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
1199 			link_stats->rssi_data) ||
1200 	    nla_put_u32(vendor_event,
1201 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
1202 			link_stats->rssi_ack) ||
1203 	    nla_put_u32(vendor_event,
1204 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
1205 			link_stats->is_leaky_ap) ||
1206 	    nla_put_u32(vendor_event,
1207 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
1208 			link_stats->avg_rx_frms_leaked) ||
1209 	    nla_put_u32(vendor_event,
1210 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
1211 			link_stats->rx_leak_window) ||
1212 	    nla_put_s32(vendor_event,
1213 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL,
1214 			link_stats->nf_cal_val) ||
1215 	    hdd_wlan_nla_put_u64(vendor_event,
1216 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
1217 			average_tsf_offset) ||
1218 	    nla_put_u32(vendor_event,
1219 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
1220 			if_stat->rts_succ_cnt) ||
1221 	    nla_put_u32(vendor_event,
1222 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
1223 			if_stat->rts_fail_cnt) ||
1224 	    nla_put_u32(vendor_event,
1225 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
1226 			if_stat->ppdu_succ_cnt) ||
1227 	    nla_put_u32(vendor_event,
1228 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
1229 			if_stat->ppdu_fail_cnt)) {
1230 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1231 		return false;
1232 	}
1233 
1234 	wmm_info = nla_nest_start(vendor_event,
1235 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
1236 	if (!wmm_info)
1237 		return false;
1238 
1239 	for (i = 0; i < WIFI_AC_MAX; i++) {
1240 		wmm_stats = nla_nest_start(vendor_event, i);
1241 		if (!wmm_stats)
1242 			return false;
1243 
1244 		if (!put_wifi_wmm_ac_stat(&if_stat->ac_stats[i],
1245 					  vendor_event)) {
1246 			hdd_err("put_wifi_wmm_ac_stat Fail");
1247 			return false;
1248 		}
1249 
1250 		nla_nest_end(vendor_event, wmm_stats);
1251 	}
1252 	nla_nest_end(vendor_event, wmm_info);
1253 
1254 	if (nla_put_u32(vendor_event,
1255 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON,
1256 			if_stat->powersave_stats.tot_tim_bcn) ||
1257 	    nla_put_u32(vendor_event,
1258 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR,
1259 			if_stat->powersave_stats.tot_err_tim_bcn)) {
1260 		hdd_err("QCA_WLAN_VENDOR_ATTR put powersave_stat fail");
1261 		return false;
1262 	}
1263 
1264 	return true;
1265 }
1266 
1267 /**
1268  * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
1269  * @device_mode: Device mode
1270  *
1271  * Return: interface mode
1272  */
hdd_map_device_to_ll_iface_mode(int device_mode)1273 static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int device_mode)
1274 {
1275 	switch (device_mode) {
1276 	case QDF_STA_MODE:
1277 		return WIFI_INTERFACE_STA;
1278 	case QDF_SAP_MODE:
1279 		return WIFI_INTERFACE_SOFTAP;
1280 	case QDF_P2P_CLIENT_MODE:
1281 		return WIFI_INTERFACE_P2P_CLIENT;
1282 	case QDF_P2P_GO_MODE:
1283 		return WIFI_INTERFACE_P2P_GO;
1284 	default:
1285 		/* Return Interface Mode as STA for all the unsupported modes */
1286 		return WIFI_INTERFACE_STA;
1287 	}
1288 }
1289 
hdd_get_interface_info(struct wlan_hdd_link_info * link_info,struct wifi_interface_info * info)1290 bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info,
1291 			    struct wifi_interface_info *info)
1292 {
1293 	struct hdd_station_ctx *sta_ctx;
1294 	struct sap_config *config;
1295 	struct qdf_mac_addr *mac;
1296 	struct hdd_adapter *adapter = link_info->adapter;
1297 
1298 	info->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
1299 
1300 	mac = hdd_adapter_get_link_mac_addr(link_info);
1301 	if (!mac) {
1302 		hdd_debug("Invalid HDD link info");
1303 		return false;
1304 	}
1305 
1306 	qdf_copy_macaddr(&info->macAddr, mac);
1307 
1308 	if (((QDF_STA_MODE == adapter->device_mode) ||
1309 	     (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
1310 	     (QDF_P2P_DEVICE_MODE == adapter->device_mode))) {
1311 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1312 		if (hdd_cm_is_disconnected(link_info))
1313 			info->state = WIFI_DISCONNECTED;
1314 
1315 		if (hdd_cm_is_connecting(link_info)) {
1316 			hdd_debug("Session ID %d, Connection is in progress",
1317 				  link_info->vdev_id);
1318 			info->state = WIFI_ASSOCIATING;
1319 		}
1320 		if (hdd_cm_is_vdev_associated(link_info) &&
1321 		    !sta_ctx->conn_info.is_authenticated) {
1322 			hdd_err("client " QDF_MAC_ADDR_FMT
1323 				" is in the middle of WPS/EAPOL exchange.",
1324 				QDF_MAC_ADDR_REF(mac->bytes));
1325 			info->state = WIFI_AUTHENTICATING;
1326 		}
1327 		if (hdd_cm_is_vdev_associated(link_info) ||
1328 		    link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
1329 			info->state = WIFI_ASSOCIATED;
1330 			qdf_copy_macaddr(&info->bssid,
1331 					 &sta_ctx->conn_info.bssid);
1332 			qdf_mem_copy(info->ssid,
1333 				     sta_ctx->conn_info.ssid.SSID.ssId,
1334 				     sta_ctx->conn_info.ssid.SSID.length);
1335 			/*
1336 			 * NULL Terminate the string
1337 			 */
1338 			info->ssid[sta_ctx->conn_info.ssid.SSID.length] = 0;
1339 		}
1340 	}
1341 
1342 	if ((adapter->device_mode == QDF_SAP_MODE ||
1343 	     adapter->device_mode == QDF_P2P_GO_MODE) &&
1344 	    test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
1345 		config = &link_info->session.ap.sap_config;
1346 		qdf_copy_macaddr(&info->bssid, &config->self_macaddr);
1347 	}
1348 	wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->countryStr);
1349 	wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->apCountryStr);
1350 
1351 	return true;
1352 }
1353 
1354 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
1355 /**
1356  * hdd_cache_ll_iface_stats() - Caches ll_stats received from fw
1357  * @hdd_ctx: Pointer to hdd_context
1358  * @if_stat: Pointer to stats data
1359  *
1360  * After receiving Link Layer Interface statistics from FW.
1361  * This function caches them into wlan_hdd_link_info.
1362  *
1363  * Return: None
1364  */
1365 static void
hdd_cache_ll_iface_stats(struct hdd_context * hdd_ctx,struct wifi_interface_stats * if_stat)1366 hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
1367 			 struct wifi_interface_stats *if_stat)
1368 {
1369 	struct wlan_hdd_link_info *link_info;
1370 
1371 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, if_stat->vdev_id);
1372 	if (!link_info) {
1373 		hdd_err("Invalid link_info. Unable to cache mlo iface stats");
1374 		return;
1375 	}
1376 	/*
1377 	 * There is no need for wlan_hdd_validate_context here. This is a NB
1378 	 * operation that will come with DSC synchronization. This ensures that
1379 	 * no driver transition will take place as long as this operation is
1380 	 * not complete. Thus the need to check validity of hdd_context is not
1381 	 * required.
1382 	 */
1383 	hdd_nofl_debug("Copying iface stats for vdev_id[%u] into link_info",
1384 		       link_info->vdev_id);
1385 	link_info->ll_iface_stats = *if_stat;
1386 }
1387 
1388 /**
1389  * wlan_hdd_update_wmm_ac_stats() - Populate ll_iface ac stats
1390  * @link_info: Link info pointer of STA adapter
1391  * @if_stat: Pointer to wifi_interface_stats structure
1392  * @update_contention_stats: whether to update contention stats or not
1393  *
1394  * Return: none
1395  */
1396 static void
wlan_hdd_update_wmm_ac_stats(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat,bool update_contention_stats)1397 wlan_hdd_update_wmm_ac_stats(struct wlan_hdd_link_info *link_info,
1398 			     struct wifi_interface_stats *if_stat,
1399 			     bool update_contention_stats)
1400 {
1401 	int i;
1402 	wmi_wmm_ac_stats *hdd_ac_stats, *stats;
1403 
1404 	for (i = 0; i < WIFI_AC_MAX; i++) {
1405 		hdd_ac_stats = &link_info->ll_iface_stats.ac_stats[i];
1406 		stats = &if_stat->ac_stats[i];
1407 		stats->ac_type = hdd_ac_stats->ac_type;
1408 		stats->tx_mpdu += hdd_ac_stats->tx_mpdu;
1409 		stats->rx_mpdu += hdd_ac_stats->rx_mpdu;
1410 		stats->tx_mcast += hdd_ac_stats->tx_mcast;
1411 		stats->rx_mcast += hdd_ac_stats->rx_mcast;
1412 		stats->rx_ampdu += hdd_ac_stats->rx_ampdu;
1413 		stats->tx_ampdu += hdd_ac_stats->tx_ampdu;
1414 		stats->mpdu_lost += hdd_ac_stats->mpdu_lost;
1415 		stats->retries += hdd_ac_stats->retries;
1416 		stats->retries_short += hdd_ac_stats->retries_short;
1417 		stats->retries_long += hdd_ac_stats->retries_long;
1418 		if (!update_contention_stats)
1419 			continue;
1420 		stats->contention_time_min = hdd_ac_stats->contention_time_min;
1421 		stats->contention_time_max = hdd_ac_stats->contention_time_max;
1422 		stats->contention_time_avg = hdd_ac_stats->contention_time_avg;
1423 		stats->contention_num_samples =
1424 					hdd_ac_stats->contention_num_samples;
1425 	}
1426 }
1427 
1428 /**
1429  * wlan_hdd_update_iface_stats_info() - Populate ll_iface stats info
1430  * @link_info: Link info pointer of STA adapter
1431  * @if_stat: Pointer to wifi_interface_stats structure
1432  * @update_stats: whether to update iface stats
1433  *
1434  * Return: none
1435  */
1436 static void
wlan_hdd_update_iface_stats_info(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat,bool update_stats)1437 wlan_hdd_update_iface_stats_info(struct wlan_hdd_link_info *link_info,
1438 				 struct wifi_interface_stats *if_stat,
1439 				 bool update_stats)
1440 {
1441 	wmi_iface_link_stats *hdd_stats, *stats;
1442 
1443 	hdd_stats = &link_info->ll_iface_stats.link_stats;
1444 	stats = &if_stat->link_stats;
1445 
1446 	if (!update_stats) {
1447 		wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats);
1448 		return;
1449 	}
1450 
1451 	stats->beacon_rx = hdd_stats->beacon_rx;
1452 	stats->mgmt_rx = hdd_stats->mgmt_rx;
1453 	stats->mgmt_action_rx = hdd_stats->mgmt_action_rx;
1454 	stats->mgmt_action_tx = hdd_stats->mgmt_action_tx;
1455 	stats->rssi_mgmt = hdd_stats->rssi_mgmt;
1456 	stats->rssi_data = hdd_stats->rssi_data;
1457 	stats->rssi_ack = hdd_stats->rssi_ack;
1458 	stats->avg_bcn_spread_offset_low =
1459 			hdd_stats->avg_bcn_spread_offset_low;
1460 	stats->avg_bcn_spread_offset_high =
1461 			hdd_stats->avg_bcn_spread_offset_high;
1462 	stats->is_leaky_ap = hdd_stats->is_leaky_ap;
1463 	stats->avg_rx_frms_leaked = hdd_stats->avg_rx_frms_leaked;
1464 	stats->rx_leak_window = hdd_stats->rx_leak_window;
1465 	stats->nf_cal_val = hdd_stats->nf_cal_val;
1466 	stats->num_peers = hdd_stats->num_peers;
1467 	stats->num_ac = hdd_stats->num_ac;
1468 
1469 	if_stat->rts_succ_cnt = link_info->ll_iface_stats.rts_succ_cnt;
1470 	if_stat->rts_fail_cnt = link_info->ll_iface_stats.rts_fail_cnt;
1471 	if_stat->ppdu_succ_cnt = link_info->ll_iface_stats.ppdu_succ_cnt;
1472 	if_stat->ppdu_fail_cnt = link_info->ll_iface_stats.ppdu_fail_cnt;
1473 
1474 	if_stat->powersave_stats.tot_tim_bcn =
1475 		link_info->ll_iface_stats.powersave_stats.tot_tim_bcn;
1476 	if_stat->powersave_stats.tot_err_tim_bcn =
1477 		link_info->ll_iface_stats.powersave_stats.tot_err_tim_bcn;
1478 
1479 	wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats);
1480 }
1481 
1482 /**
1483  * wlan_hdd_copy_mlo_peer_stats() - copy mlo peer stats to link_info
1484  * @adapter: Pointer to HDD adapter
1485  * @peer_stat: Pointer to wifi_peer_stat
1486  *
1487  * Return: none
1488  */
1489 static void
wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter * adapter,struct wifi_peer_stat * peer_stat)1490 wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter,
1491 			     struct wifi_peer_stat *peer_stat)
1492 {
1493 	uint8_t i, j, num_rate;
1494 	struct wifi_peer_info *peer_info = NULL;
1495 	struct wifi_rate_stat *rate_stat;
1496 	struct wlan_hdd_link_info *link_info;
1497 	struct hdd_station_ctx *sta_ctx;
1498 
1499 	if (!peer_stat) {
1500 		hdd_err("Invalid mlo peer stats");
1501 		return;
1502 	}
1503 
1504 	if (!peer_stat->num_peers) {
1505 		hdd_err("No mlo peers");
1506 		return;
1507 	}
1508 
1509 	/* Firmware doesn't send peer stats for stanby link, but we need to
1510 	 * send peer stats for stanby link as well to userspace. So, in that
1511 	 * case we fill partial values for stanby link and full stats received
1512 	 * from firmware for active links and set the flag stats_cached in
1513 	 * the link_info->mlo_peer_info structure.
1514 	 */
1515 
1516 	peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
1517 
1518 	hdd_adapter_for_each_link_info(adapter, link_info) {
1519 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1520 		link_info->mlo_peer_info.link_id =
1521 						sta_ctx->conn_info.ieee_link_id;
1522 
1523 		if (link_info->mlo_peer_info.stats_cached)
1524 			continue;
1525 
1526 		/* since for stanby link we don't have valid values from
1527 		 * firmware, we just fill peer mac and link id.
1528 		 */
1529 		qdf_mem_copy(&link_info->mlo_peer_info.peer_mac,
1530 			     &sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE);
1531 		link_info->mlo_peer_info.type = peer_info->type;
1532 		link_info->mlo_peer_info.num_rate = HDD_MAX_PER_PEER_RATES;
1533 		for (j = 0; j < HDD_MAX_PER_PEER_RATES; j++)
1534 			qdf_mem_zero(&link_info->mlo_peer_info.rate_stats[j],
1535 				     sizeof(struct wifi_rate_stat));
1536 		hdd_debug("Default values for standby link " QDF_MAC_ADDR_FMT,
1537 			  QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes));
1538 	}
1539 
1540 	for (i = 1; i <= peer_stat->num_peers; i++) {
1541 		link_info = hdd_get_link_info_by_bssid(adapter->hdd_ctx,
1542 						peer_info->peer_macaddr.bytes);
1543 		if (!link_info) {
1544 			hdd_err("invalid link_info");
1545 			continue;
1546 		}
1547 
1548 		num_rate = peer_info->num_rate;
1549 		if (num_rate > HDD_MAX_PER_PEER_RATES) {
1550 			hdd_err("For peer " QDF_MAC_ADDR_FMT " got %u rate stats, expected %d",
1551 				QDF_MAC_ADDR_REF(peer_info->peer_macaddr.bytes),
1552 				num_rate, HDD_MAX_PER_PEER_RATES);
1553 			return;
1554 		}
1555 
1556 		link_info->mlo_peer_info.type = peer_info->type;
1557 		qdf_mem_copy(&link_info->mlo_peer_info.peer_mac,
1558 			     &peer_info->peer_macaddr, QDF_MAC_ADDR_SIZE);
1559 		link_info->mlo_peer_info.capabilities = peer_info->capabilities;
1560 		link_info->mlo_peer_info.num_rate = peer_info->num_rate;
1561 		link_info->mlo_peer_info.power_saving = peer_info->power_saving;
1562 
1563 		for (j = 0; j < num_rate; j++) {
1564 			rate_stat = &peer_info->rate_stats[j];
1565 			qdf_mem_copy(&link_info->mlo_peer_info.rate_stats[j],
1566 				     rate_stat, sizeof(struct wifi_rate_stat));
1567 		}
1568 
1569 		/* peer stats for active link are cached in link_info
1570 		 * so set the flag stats_cahed to true.
1571 		 */
1572 		link_info->mlo_peer_info.stats_cached = true;
1573 
1574 		peer_info = (struct wifi_peer_info *)
1575 				((uint8_t *)peer_stat->peer_info +
1576 				(i * sizeof(struct wifi_peer_info)) +
1577 				(num_rate * sizeof(struct wifi_rate_stat)));
1578 	}
1579 	hdd_debug_rl("Copied MLO Peer stats into link_info");
1580 }
1581 
1582 /**
1583  * wlan_hdd_put_mlo_peer_info() - send mlo peer info to userspace
1584  * @link_info: Link info pointer of STA adapter
1585  * @skb: Pointer to vendor event
1586  *
1587  * Return: none
1588  */
wlan_hdd_put_mlo_peer_info(struct wlan_hdd_link_info * link_info,struct sk_buff * skb)1589 static bool wlan_hdd_put_mlo_peer_info(struct wlan_hdd_link_info *link_info,
1590 				       struct sk_buff *skb)
1591 {
1592 	struct wifi_rate_stat *rate_stat;
1593 	struct nlattr *rate_nest, *rates;
1594 	int rate_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
1595 	uint8_t i;
1596 
1597 	if (!link_info) {
1598 		hdd_err("Invalid link_info");
1599 		return false;
1600 	}
1601 
1602 	if (nla_put_u32(skb,
1603 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
1604 			wmi_to_sir_peer_type(link_info->mlo_peer_info.type)) ||
1605 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
1606 		    QDF_MAC_ADDR_SIZE,
1607 		    &link_info->mlo_peer_info.peer_mac.bytes[0]) ||
1608 	    nla_put_u32(skb,
1609 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
1610 			link_info->mlo_peer_info.capabilities) ||
1611 	    nla_put_u32(skb,
1612 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
1613 			link_info->mlo_peer_info.num_rate) ||
1614 	    nla_put_u8(skb,
1615 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
1616 		       link_info->mlo_peer_info.link_id)) {
1617 		hdd_err("put mlo peer info fail");
1618 		return false;
1619 	}
1620 
1621 	/* no rates is ok */
1622 	if (!link_info->mlo_peer_info.num_rate)
1623 		return true;
1624 
1625 	rate_nest = nla_nest_start(skb, rate_nest_id);
1626 	if (!rate_nest)
1627 		return false;
1628 
1629 	for (i = 0; i < link_info->mlo_peer_info.num_rate; i++) {
1630 		rates = nla_nest_start(skb, i);
1631 		if (!rates)
1632 			return false;
1633 		rate_stat = &link_info->mlo_peer_info.rate_stats[i];
1634 		if (!put_wifi_rate_stat(rate_stat, skb)) {
1635 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1636 			return false;
1637 		}
1638 		nla_nest_end(skb, rates);
1639 	}
1640 	nla_nest_end(skb, rate_nest);
1641 
1642 	return true;
1643 }
1644 
1645 /**
1646  * wlan_hdd_send_mlo_ll_peer_stats_to_user() - send mlo ll peer stats to userspace
1647  * @adapter: Pointer to HDD adapter
1648  *
1649  * Return: none
1650  */
1651 static void
wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter * adapter)1652 wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter)
1653 {
1654 	struct sk_buff *skb;
1655 	struct nlattr *peers, *peer_nest;
1656 	struct wlan_hdd_link_info *link_info;
1657 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1658 	int peer_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO;
1659 	u32 num_peers;
1660 	uint8_t i = 0;
1661 
1662 	wlan_hdd_get_mlo_links_count(adapter, &num_peers);
1663 
1664 	hdd_debug_rl("WMI_MLO_LINK_STATS_PEER. Num Peers: %u", num_peers);
1665 
1666 	if (!num_peers) {
1667 		hdd_err("No mlo peers");
1668 		return;
1669 	}
1670 
1671 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(adapter->hdd_ctx->wiphy,
1672 						       LL_STATS_EVENT_BUF_SIZE);
1673 	if (!skb) {
1674 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1675 		return;
1676 	}
1677 
1678 	if (nla_put_u32(skb,
1679 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1680 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) ||
1681 	    nla_put_u32(skb,
1682 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
1683 			adapter->hdd_ctx->more_peer_data) ||
1684 	    nla_put_u32(skb,
1685 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
1686 			num_peers)) {
1687 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1688 
1689 		goto exit;
1690 	}
1691 
1692 	peer_nest = nla_nest_start(skb, peer_nest_id);
1693 	if (!peer_nest) {
1694 		hdd_err("nla_nest_start failed");
1695 		goto exit;
1696 	}
1697 
1698 	hdd_adapter_for_each_link_info(adapter, link_info) {
1699 		wlan_hdd_get_connected_link_info(link_info, &info);
1700 		if (info.link_id == WLAN_INVALID_LINK_ID)
1701 			continue;
1702 
1703 		peers = nla_nest_start(skb, i);
1704 		if (!peers) {
1705 			hdd_err("nla_nest_start failed");
1706 			goto exit;
1707 		}
1708 
1709 		if (!wlan_hdd_put_mlo_peer_info(link_info, skb)) {
1710 			hdd_err("put_wifi_peer_info fail");
1711 			goto exit;
1712 		}
1713 		nla_nest_end(skb, peers);
1714 		i++;
1715 	}
1716 	nla_nest_end(skb, peer_nest);
1717 
1718 	wlan_cfg80211_vendor_cmd_reply(skb);
1719 
1720 	hdd_debug_rl("Sent %u MLO Peer stats to User Space", i);
1721 	return;
1722 exit:
1723 	wlan_cfg80211_vendor_free_skb(skb);
1724 }
1725 
1726 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
1727 /**
1728  * wlan_hdd_get_iface_stats() - Get ll_iface stats info from link_info
1729  * @link_info: Link info pointer of STA adapter
1730  * @if_stat: Pointer to wifi_interface_stats structure
1731  *
1732  * Return: 0 on success, error on failure
1733  */
wlan_hdd_get_iface_stats(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat)1734 static int wlan_hdd_get_iface_stats(struct wlan_hdd_link_info *link_info,
1735 				    struct wifi_interface_stats *if_stat)
1736 {
1737 	if (!link_info || !if_stat) {
1738 		hdd_err("Invalid link_info or interface stats");
1739 		return -EINVAL;
1740 	}
1741 
1742 	qdf_mem_copy(if_stat, &link_info->ll_iface_stats,
1743 		     sizeof(link_info->ll_iface_stats));
1744 
1745 	if (!hdd_get_interface_info(link_info, &if_stat->info)) {
1746 		hdd_err("Unable to get iface info for vdev[%u]",
1747 			if_stat->vdev_id);
1748 		return -EINVAL;
1749 	}
1750 
1751 	return 0;
1752 }
1753 
1754 static bool
wlan_hdd_get_mlo_iface_info(struct hdd_context * hdd_ctx,struct wifi_interface_stats * stats,struct wlan_hdd_mlo_iface_stats_info * info)1755 wlan_hdd_get_mlo_iface_info(struct hdd_context *hdd_ctx,
1756 			    struct wifi_interface_stats *stats,
1757 			    struct wlan_hdd_mlo_iface_stats_info *info)
1758 {
1759 	struct wlan_hdd_link_info *link_info;
1760 	struct hdd_station_ctx *sta_ctx;
1761 
1762 	if (!stats) {
1763 		hdd_err("invalid wifi interface stats");
1764 		return false;
1765 	}
1766 
1767 	link_info = hdd_get_link_info_by_bssid(hdd_ctx,
1768 				(const uint8_t *)stats->info.bssid.bytes);
1769 
1770 	if (!link_info) {
1771 		hdd_err("invalid link_info");
1772 		return false;
1773 	}
1774 
1775 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1776 	info->link_id = sta_ctx->conn_info.ieee_link_id;
1777 	info->freq = sta_ctx->conn_info.chan_freq;
1778 
1779 	return true;
1780 }
1781 
1782 /**
1783  * wlan_hdd_send_mlo_ll_iface_stats_to_user() - send mlo ll stats to userspace
1784  * @adapter: Pointer to adapter
1785  *
1786  * Return: none
1787  */
1788 static void
wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter * adapter)1789 wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
1790 {
1791 	struct hdd_mlo_adapter_info *mlo_adapter_info;
1792 	struct hdd_adapter *link_adapter, *ml_adapter;
1793 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1794 	u32 num_links, per_link_peers;
1795 	uint8_t i, j = 0;
1796 	int8_t rssi;
1797 	struct wifi_interface_stats cumulative_if_stat = {0};
1798 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1799 	struct wifi_interface_stats *link_if_stat;
1800 	bool update_stats = false;
1801 	QDF_STATUS status;
1802 	struct nlattr *ml_iface_nest, *ml_iface_links;
1803 	struct sk_buff *skb;
1804 	struct wlan_hdd_link_info *link_info;
1805 	struct qdf_mac_addr *netdev_addr;
1806 
1807 	if (wlan_hdd_validate_context(hdd_ctx)) {
1808 		hdd_err("Invalid hdd context");
1809 		return;
1810 	}
1811 
1812 	ml_adapter = adapter;
1813 	if (hdd_adapter_is_link_adapter(adapter))
1814 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
1815 
1816 	link_info = ml_adapter->deflink;
1817 	rssi = link_info->rssi;
1818 	wlan_hdd_get_mlo_links_count(adapter, &num_links);
1819 
1820 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1821 						       LL_STATS_EVENT_BUF_SIZE);
1822 
1823 	if (!skb) {
1824 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1825 		return;
1826 	}
1827 
1828 	link_if_stat = qdf_mem_malloc(sizeof(*link_if_stat) * num_links);
1829 	if (!link_if_stat) {
1830 		hdd_err("failed to allocate memory for link iface stat");
1831 		goto err;
1832 	}
1833 
1834 	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links);
1835 
1836 	if (!hdd_get_interface_info(link_info, &cumulative_if_stat.info)) {
1837 		hdd_err("hdd_get_interface_info get fail for ml_adapter");
1838 		goto err;
1839 	}
1840 
1841 	wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
1842 					 true);
1843 
1844 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
1845 	for (i = 0; i < WLAN_MAX_MLD; i++) {
1846 		link_adapter = mlo_adapter_info->link_adapter[i];
1847 
1848 		if (!link_adapter)
1849 			continue;
1850 
1851 		link_info = link_adapter->deflink;
1852 		if (!hdd_cm_is_vdev_associated(link_info)) {
1853 			hdd_debug_rl("vdev_id[%u] is not associated\n",
1854 				     link_info->vdev_id);
1855 			continue;
1856 		}
1857 
1858 		if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) {
1859 			if (wlan_hdd_get_iface_stats(ml_adapter->deflink,
1860 						     &link_if_stat[j]))
1861 				goto err;
1862 			j++;
1863 			if (j == num_links)
1864 				break;
1865 			continue;
1866 		}
1867 
1868 		if (wlan_hdd_get_iface_stats(link_info, &link_if_stat[j]))
1869 			goto err;
1870 		j++;
1871 		if (j == num_links)
1872 			break;
1873 
1874 		if (rssi <= link_info->rssi) {
1875 			rssi = link_info->rssi;
1876 			update_stats = true;
1877 		}
1878 
1879 		wlan_hdd_update_iface_stats_info(link_info,
1880 						 &cumulative_if_stat,
1881 						 update_stats);
1882 	}
1883 
1884 	netdev_addr = hdd_adapter_get_netdev_mac_addr(ml_adapter);
1885 	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
1886 
1887 	status = wlan_hdd_get_bss_peer_mld_mac(ml_adapter->deflink,
1888 					       &cumulative_if_stat.info.bssid);
1889 	if (QDF_IS_STATUS_ERROR(status))
1890 		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
1891 
1892 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb,
1893 				  ml_adapter->deflink)) {
1894 		hdd_err("put_wifi_iface_stats fail");
1895 		goto err;
1896 	}
1897 
1898 	ml_iface_nest = nla_nest_start(skb,
1899 				       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK);
1900 	if (!ml_iface_nest) {
1901 		hdd_err("Nesting mlo iface stats info failed");
1902 		goto err;
1903 	}
1904 
1905 	for (i = 0; i < num_links; i++) {
1906 		ml_iface_links = nla_nest_start(skb, i);
1907 		if (!ml_iface_links) {
1908 			hdd_err("per link mlo iface stats failed");
1909 			goto err;
1910 		}
1911 
1912 		per_link_peers =
1913 			link_info->ll_iface_stats.link_stats.num_peers;
1914 
1915 		if (!wlan_hdd_get_mlo_iface_info(hdd_ctx,
1916 						 &link_if_stat[i], &info))
1917 			goto err;
1918 
1919 		if (!wlan_hdd_put_mlo_link_iface_info(&info, skb))
1920 			goto err;
1921 
1922 		if (!put_wifi_iface_stats(&link_if_stat[i],
1923 					  per_link_peers, skb, link_info)) {
1924 			hdd_err("put_wifi_iface_stats failed for link[%u]", i);
1925 			goto err;
1926 		}
1927 
1928 		nla_nest_end(skb, ml_iface_links);
1929 	}
1930 	nla_nest_end(skb, ml_iface_nest);
1931 
1932 	wlan_cfg80211_vendor_cmd_reply(skb);
1933 	qdf_mem_free(link_if_stat);
1934 	hdd_nofl_debug("Sent mlo interface stats to userspace");
1935 	return;
1936 err:
1937 	wlan_cfg80211_vendor_free_skb(skb);
1938 	qdf_mem_free(link_if_stat);
1939 }
1940 #else
1941 static void
wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter * adapter)1942 wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
1943 {
1944 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1945 	u32 num_links, per_link_peers;
1946 	uint8_t i = 0;
1947 	int8_t rssi = WLAN_INVALID_RSSI_VALUE;
1948 	struct wifi_interface_stats cumulative_if_stat = {0};
1949 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1950 	struct wifi_interface_stats *stats;
1951 	struct wifi_interface_info *iface_info;
1952 	bool update_stats;
1953 	QDF_STATUS status;
1954 	struct nlattr *ml_iface_nest, *ml_iface_links;
1955 	struct sk_buff *skb;
1956 	struct wlan_hdd_link_info *link_info;
1957 	struct qdf_mac_addr *netdev_addr;
1958 	int8_t rssi_data;
1959 
1960 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
1961 		return;
1962 
1963 	if (wlan_hdd_validate_context(hdd_ctx)) {
1964 		hdd_err("Invalid hdd context");
1965 		return;
1966 	}
1967 
1968 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1969 						       LL_STATS_EVENT_BUF_SIZE);
1970 
1971 	if (!skb) {
1972 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1973 		return;
1974 	}
1975 
1976 	wlan_hdd_get_mlo_links_count(adapter, &num_links);
1977 
1978 	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links);
1979 
1980 	hdd_adapter_for_each_link_info(adapter, link_info) {
1981 		wlan_hdd_get_connected_link_info(link_info, &info);
1982 
1983 		if (info.link_id == WLAN_INVALID_LINK_ID)
1984 			continue;
1985 
1986 		rssi_data = link_info->ll_iface_stats.link_stats.rssi_data;
1987 
1988 		if ((link_info->adapter->device_mode == QDF_P2P_GO_MODE ||
1989 		     link_info->adapter->device_mode == QDF_SAP_MODE) &&
1990 		    rssi <= rssi_data) {
1991 			rssi = rssi_data;
1992 			update_stats = true;
1993 			if (!hdd_get_interface_info(link_info,
1994 						    &cumulative_if_stat.info)) {
1995 				hdd_err("failed to get iface info for link %u",
1996 					info.link_id);
1997 				goto err;
1998 			}
1999 		} else if (rssi_data != 0 && (rssi <= rssi_data)) {
2000 			rssi = rssi_data;
2001 			update_stats = true;
2002 			if (!hdd_get_interface_info(link_info,
2003 						    &cumulative_if_stat.info)) {
2004 				hdd_err("failed to get iface info for link %u",
2005 					info.link_id);
2006 				goto err;
2007 			}
2008 		} else {
2009 			update_stats = false;
2010 		}
2011 
2012 		iface_info = &link_info->ll_iface_stats.info;
2013 		if (!hdd_get_interface_info(link_info, iface_info)) {
2014 			hdd_err("get iface info failed for link %u", info.link_id);
2015 			goto err;
2016 		}
2017 
2018 		wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
2019 						 update_stats);
2020 	}
2021 
2022 	netdev_addr = hdd_adapter_get_netdev_mac_addr(adapter);
2023 	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
2024 
2025 	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink,
2026 					       &cumulative_if_stat.info.bssid);
2027 	if (QDF_IS_STATUS_ERROR(status))
2028 		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
2029 
2030 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb,
2031 				  adapter->deflink)) {
2032 		hdd_err("put_wifi_iface_stats fail");
2033 		goto err;
2034 	}
2035 
2036 	ml_iface_nest =
2037 		nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK);
2038 
2039 	if (!ml_iface_nest) {
2040 		hdd_err("Nesting mlo iface stats info failed");
2041 		goto err;
2042 	}
2043 
2044 	hdd_adapter_for_each_link_info(adapter, link_info) {
2045 		wlan_hdd_get_connected_link_info(link_info, &info);
2046 
2047 		if (info.link_id == WLAN_INVALID_LINK_ID)
2048 			continue;
2049 
2050 		ml_iface_links = nla_nest_start(skb, i);
2051 		if (!ml_iface_links) {
2052 			hdd_err("per link mlo iface stats failed");
2053 			goto err;
2054 		}
2055 
2056 		stats = &link_info->ll_iface_stats;
2057 		per_link_peers = stats->link_stats.num_peers;
2058 
2059 		if (!wlan_hdd_put_mlo_link_iface_info(&info, skb))
2060 			goto err;
2061 
2062 		if (!put_wifi_iface_stats(stats, per_link_peers, skb,
2063 					  link_info)) {
2064 			hdd_err("put iface stats failed for link[%u]", info.link_id);
2065 			goto err;
2066 		}
2067 
2068 		nla_nest_end(skb, ml_iface_links);
2069 		i++;
2070 	}
2071 	nla_nest_end(skb, ml_iface_nest);
2072 
2073 	wlan_cfg80211_vendor_cmd_reply(skb);
2074 	hdd_nofl_debug("Sent mlo interface stats to userspace");
2075 	return;
2076 err:
2077 	wlan_cfg80211_vendor_free_skb(skb);
2078 }
2079 #endif
2080 #else
2081 static void
hdd_cache_ll_iface_stats(struct hdd_context * hdd_ctx,struct wifi_interface_stats * if_stat)2082 hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
2083 			 struct wifi_interface_stats *if_stat)
2084 {
2085 }
2086 
2087 static inline void
wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter * adapter)2088 wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
2089 {
2090 }
2091 
2092 static inline void
wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter * adapter)2093 wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter)
2094 {
2095 }
2096 
2097 static inline bool
wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter * adapter,struct wifi_peer_stat * peer_stat)2098 wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter,
2099 			     struct wifi_peer_stat *peer_stat)
2100 {
2101 	return true;
2102 }
2103 #endif
2104 
2105 /**
2106  * hdd_link_layer_process_peer_stats() - This function is called after
2107  * @adapter: Pointer to device adapter
2108  * @more_data: More data
2109  * @peer_stat: Pointer to stats data
2110  *
2111  * Receiving Link Layer Peer statistics from FW.This function converts
2112  * the firmware data to the NL data and sends the same to the kernel/upper
2113  * layers.
2114  *
2115  * Return: None
2116  */
hdd_link_layer_process_peer_stats(struct hdd_adapter * adapter,u32 more_data,struct wifi_peer_stat * peer_stat)2117 static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
2118 					      u32 more_data,
2119 					      struct wifi_peer_stat *peer_stat)
2120 {
2121 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2122 	struct wifi_peer_info *peer_info;
2123 	struct sk_buff *skb;
2124 	int i, nestid;
2125 	struct nlattr *peers;
2126 	int num_rate;
2127 
2128 	if (wlan_hdd_validate_context(hdd_ctx))
2129 		return;
2130 
2131 	if ((adapter->device_mode == QDF_STA_MODE ||
2132 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
2133 	    wlan_hdd_is_mlo_connection(adapter->deflink)) {
2134 		wlan_hdd_copy_mlo_peer_stats(adapter, peer_stat);
2135 		return;
2136 	}
2137 
2138 	hdd_nofl_debug("LL_STATS_PEER_ALL : num_peers %u, more data = %u",
2139 		       peer_stat->num_peers, more_data);
2140 
2141 	/*
2142 	 * Allocate a size of 4096 for the peer stats comprising
2143 	 * each of size = sizeof (struct wifi_peer_info) + num_rate *
2144 	 * sizeof (struct wifi_rate_stat).Each field is put with an
2145 	 * NL attribute.The size of 4096 is considered assuming
2146 	 * that number of rates shall not exceed beyond 50 with
2147 	 * the sizeof (struct wifi_rate_stat) being 32.
2148 	 */
2149 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
2150 						       LL_STATS_EVENT_BUF_SIZE);
2151 
2152 	if (!skb) {
2153 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2154 		return;
2155 	}
2156 
2157 	if (nla_put_u32(skb,
2158 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
2159 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) ||
2160 	    nla_put_u32(skb,
2161 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
2162 			more_data) ||
2163 	    nla_put_u32(skb,
2164 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
2165 			peer_stat->num_peers)) {
2166 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2167 
2168 		wlan_cfg80211_vendor_free_skb(skb);
2169 		return;
2170 	}
2171 
2172 	peer_info = (struct wifi_peer_info *) ((uint8_t *)
2173 					     peer_stat->peer_info);
2174 
2175 	if (peer_stat->num_peers) {
2176 		struct nlattr *peer_nest;
2177 
2178 		nestid = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO;
2179 		peer_nest = nla_nest_start(skb, nestid);
2180 		if (!peer_nest) {
2181 			hdd_err("nla_nest_start failed");
2182 			wlan_cfg80211_vendor_free_skb(skb);
2183 			return;
2184 		}
2185 
2186 		for (i = 1; i <= peer_stat->num_peers; i++) {
2187 			peers = nla_nest_start(skb, i);
2188 			if (!peers) {
2189 				hdd_err("nla_nest_start failed");
2190 				wlan_cfg80211_vendor_free_skb(skb);
2191 				return;
2192 			}
2193 
2194 			num_rate = peer_info->num_rate;
2195 
2196 			if (!put_wifi_peer_info(peer_info, skb)) {
2197 				hdd_err("put_wifi_peer_info fail");
2198 				wlan_cfg80211_vendor_free_skb(skb);
2199 				return;
2200 			}
2201 
2202 			peer_info = (struct wifi_peer_info *)
2203 				((uint8_t *)peer_stat->peer_info +
2204 				 (i * sizeof(struct wifi_peer_info)) +
2205 				 (num_rate * sizeof(struct wifi_rate_stat)));
2206 			nla_nest_end(skb, peers);
2207 		}
2208 		nla_nest_end(skb, peer_nest);
2209 	}
2210 
2211 	wlan_cfg80211_vendor_cmd_reply(skb);
2212 }
2213 
2214 /**
2215  * hdd_link_layer_process_iface_stats() - This function is called after
2216  * @link_info: Link info pointer in HDD adapter
2217  * @if_stat: Pointer to stats data
2218  * @num_peers: Number of peers
2219  *
2220  * Receiving Link Layer Interface statistics from FW.This function converts
2221  * the firmware data to the NL data and sends the same to the kernel/upper
2222  * layers.
2223  *
2224  * Return: None
2225  */
2226 static void
hdd_link_layer_process_iface_stats(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat,u32 num_peers)2227 hdd_link_layer_process_iface_stats(struct wlan_hdd_link_info *link_info,
2228 				   struct wifi_interface_stats *if_stat,
2229 				   u32 num_peers)
2230 {
2231 	struct sk_buff *skb;
2232 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2233 
2234 	if (wlan_hdd_is_mlo_connection(link_info)) {
2235 		hdd_cache_ll_iface_stats(hdd_ctx, if_stat);
2236 		return;
2237 	}
2238 
2239 	/*
2240 	 * There is no need for wlan_hdd_validate_context here. This is a NB
2241 	 * operation that will come with DSC synchronization. This ensures that
2242 	 * no driver transition will take place as long as this operation is
2243 	 * not complete. Thus the need to check validity of hdd_context is not
2244 	 * required.
2245 	 */
2246 
2247 	/*
2248 	 * Allocate a size of 4096 for the interface stats comprising
2249 	 * sizeof (struct wifi_interface_stats *).The size of 4096 is considered
2250 	 * assuming that all these fit with in the limit.Please take
2251 	 * a call on the limit based on the data requirements on
2252 	 * interface statistics.
2253 	 */
2254 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
2255 						       LL_STATS_EVENT_BUF_SIZE);
2256 
2257 	if (!skb) {
2258 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2259 		return;
2260 	}
2261 
2262 	hdd_debug("WMI_LINK_STATS_IFACE Data");
2263 
2264 	if (!hdd_get_interface_info(link_info, &if_stat->info)) {
2265 		hdd_err("hdd_get_interface_info get fail");
2266 		wlan_cfg80211_vendor_free_skb(skb);
2267 		return;
2268 	}
2269 
2270 	if (!put_wifi_iface_stats(if_stat, num_peers, skb, link_info)) {
2271 		hdd_err("put_wifi_iface_stats fail");
2272 		wlan_cfg80211_vendor_free_skb(skb);
2273 		return;
2274 	}
2275 
2276 	wlan_cfg80211_vendor_cmd_reply(skb);
2277 }
2278 
2279 /**
2280  * put_channel_stats_chload - put chload of channel stats
2281  * @vendor_event: vendor event
2282  * @channel_stats: Pointer to channel stats
2283  *
2284  * Return: bool
2285  */
put_channel_stats_chload(struct sk_buff * vendor_event,struct wifi_channel_stats * channel_stats)2286 static bool put_channel_stats_chload(struct sk_buff *vendor_event,
2287 				     struct wifi_channel_stats *channel_stats)
2288 {
2289 	uint64_t txrx_time;
2290 	uint32_t chload;
2291 
2292 	if (!channel_stats->on_time)
2293 		return true;
2294 
2295 	txrx_time = (channel_stats->tx_time + channel_stats->rx_time) * 100;
2296 	chload = qdf_do_div(txrx_time, channel_stats->on_time);
2297 
2298 	if (nla_put_u8(vendor_event,
2299 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE,
2300 		       chload))
2301 		return false;
2302 
2303 	return true;
2304 }
2305 
2306 /**
2307  * hdd_llstats_radio_fill_channels() - radio stats fill channels
2308  * @adapter: Pointer to device adapter
2309  * @radiostat: Pointer to stats data
2310  * @vendor_event: vendor event
2311  *
2312  * Return: 0 on success; errno on failure
2313  */
hdd_llstats_radio_fill_channels(struct hdd_adapter * adapter,struct wifi_radio_stats * radiostat,struct sk_buff * vendor_event)2314 static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
2315 					   struct wifi_radio_stats *radiostat,
2316 					   struct sk_buff *vendor_event)
2317 {
2318 	struct wifi_channel_stats *channel_stats;
2319 	struct nlattr *chlist;
2320 	struct nlattr *chinfo;
2321 	int i;
2322 
2323 	chlist = nla_nest_start(vendor_event,
2324 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
2325 	if (!chlist) {
2326 		hdd_err("nla_nest_start failed, %u", radiostat->num_channels);
2327 		return -EINVAL;
2328 	}
2329 
2330 	for (i = 0; i < radiostat->num_channels; i++) {
2331 		channel_stats = (struct wifi_channel_stats *) ((uint8_t *)
2332 				     radiostat->channels +
2333 				     (i * sizeof(struct wifi_channel_stats)));
2334 
2335 		chinfo = nla_nest_start(vendor_event, i);
2336 		if (!chinfo) {
2337 			hdd_err("nla_nest_start failed, chan number %u",
2338 				radiostat->num_channels);
2339 			return -EINVAL;
2340 		}
2341 
2342 		if (nla_put_u32(vendor_event,
2343 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
2344 				channel_stats->channel.width) ||
2345 		    nla_put_u32(vendor_event,
2346 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
2347 				channel_stats->channel.center_freq) ||
2348 		    nla_put_u32(vendor_event,
2349 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
2350 				channel_stats->channel.center_freq0) ||
2351 		    nla_put_u32(vendor_event,
2352 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
2353 				channel_stats->channel.center_freq1) ||
2354 		    nla_put_u32(vendor_event,
2355 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
2356 				channel_stats->on_time) ||
2357 		    nla_put_u32(vendor_event,
2358 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
2359 				channel_stats->cca_busy_time)) {
2360 			hdd_err("nla_put failed for channel info (%u, %d, %u)",
2361 				radiostat->num_channels, i,
2362 				channel_stats->channel.center_freq);
2363 			return -EINVAL;
2364 		}
2365 
2366 		if (adapter->hdd_ctx &&
2367 		    adapter->hdd_ctx->ll_stats_per_chan_rx_tx_time) {
2368 			if (nla_put_u32(
2369 				vendor_event,
2370 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME,
2371 				channel_stats->tx_time) ||
2372 			    nla_put_u32(
2373 				vendor_event,
2374 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME,
2375 				channel_stats->rx_time)) {
2376 				hdd_err("nla_put failed for tx time (%u, %d)",
2377 					radiostat->num_channels, i);
2378 				return -EINVAL;
2379 			}
2380 
2381 			if (!put_channel_stats_chload(vendor_event,
2382 						      channel_stats)) {
2383 				hdd_err("nla_put failed for chload (%u, %d)",
2384 					radiostat->num_channels, i);
2385 				return -EINVAL;
2386 			}
2387 		}
2388 
2389 		nla_nest_end(vendor_event, chinfo);
2390 	}
2391 	nla_nest_end(vendor_event, chlist);
2392 
2393 	return 0;
2394 }
2395 
2396 /**
2397  * hdd_llstats_free_radio_stats() - free wifi_radio_stats member pointers
2398  * @radiostat: Pointer to stats data
2399  *
2400  * Return: void
2401  */
hdd_llstats_free_radio_stats(struct wifi_radio_stats * radiostat)2402 static void hdd_llstats_free_radio_stats(struct wifi_radio_stats *radiostat)
2403 {
2404 	if (radiostat->total_num_tx_power_levels &&
2405 	    radiostat->tx_time_per_power_level) {
2406 		qdf_mem_free(radiostat->tx_time_per_power_level);
2407 		radiostat->tx_time_per_power_level = NULL;
2408 	}
2409 	if (radiostat->num_channels && radiostat->channels) {
2410 		qdf_mem_free(radiostat->channels);
2411 		radiostat->channels = NULL;
2412 	}
2413 }
2414 
2415 /**
2416  * hdd_llstats_post_radio_stats() - post radio stats
2417  * @adapter: Pointer to device adapter
2418  * @more_data: More data
2419  * @radiostat: Pointer to stats data
2420  * @num_radio: Number of radios
2421  *
2422  * Return: void
2423  */
hdd_llstats_post_radio_stats(struct hdd_adapter * adapter,u32 more_data,struct wifi_radio_stats * radiostat,u32 num_radio)2424 static void hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
2425 					 u32 more_data,
2426 					 struct wifi_radio_stats *radiostat,
2427 					 u32 num_radio)
2428 {
2429 	struct sk_buff *vendor_event;
2430 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2431 	int ret;
2432 
2433 	/*
2434 	 * Allocate a size of 4096 for the Radio stats comprising
2435 	 * sizeof (struct wifi_radio_stats) + num_channels * sizeof
2436 	 * (struct wifi_channel_stats).Each channel data is put with an
2437 	 * NL attribute.The size of 4096 is considered assuming that
2438 	 * number of channels shall not exceed beyond  60 with the
2439 	 * sizeof (struct wifi_channel_stats) being 24 bytes.
2440 	 */
2441 
2442 	vendor_event = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
2443 					hdd_ctx->wiphy,
2444 					LL_STATS_EVENT_BUF_SIZE);
2445 
2446 	if (!vendor_event) {
2447 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2448 		hdd_llstats_free_radio_stats(radiostat);
2449 		return;
2450 	}
2451 
2452 	if (nla_put_u32(vendor_event,
2453 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
2454 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO) ||
2455 	    nla_put_u32(vendor_event,
2456 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
2457 			more_data) ||
2458 	    nla_put_u32(vendor_event,
2459 			QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
2460 			num_radio) ||
2461 	    nla_put_u32(vendor_event,
2462 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
2463 			radiostat->radio) ||
2464 	    nla_put_u32(vendor_event,
2465 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
2466 			radiostat->on_time) ||
2467 	    nla_put_u32(vendor_event,
2468 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
2469 			radiostat->tx_time) ||
2470 	    nla_put_u32(vendor_event,
2471 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
2472 			radiostat->rx_time) ||
2473 	    nla_put_u32(vendor_event,
2474 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
2475 			radiostat->on_time_scan) ||
2476 	    nla_put_u32(vendor_event,
2477 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
2478 			radiostat->on_time_nbd) ||
2479 	    nla_put_u32(vendor_event,
2480 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
2481 			radiostat->on_time_gscan) ||
2482 	    nla_put_u32(vendor_event,
2483 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
2484 			radiostat->on_time_roam_scan) ||
2485 	    nla_put_u32(vendor_event,
2486 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
2487 			radiostat->on_time_pno_scan) ||
2488 	    nla_put_u32(vendor_event,
2489 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
2490 			radiostat->on_time_hs20) ||
2491 	    nla_put_u32(vendor_event,
2492 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
2493 			radiostat->total_num_tx_power_levels)    ||
2494 	    nla_put_u32(vendor_event,
2495 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
2496 			radiostat->num_channels)) {
2497 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2498 		hdd_llstats_free_radio_stats(radiostat);
2499 
2500 		goto failure;
2501 	}
2502 
2503 	if (radiostat->total_num_tx_power_levels) {
2504 		ret =
2505 		    nla_put(vendor_event,
2506 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
2507 			    sizeof(u32) *
2508 			    radiostat->total_num_tx_power_levels,
2509 			    radiostat->tx_time_per_power_level);
2510 		if (ret) {
2511 			hdd_err("nla_put fail");
2512 			goto failure;
2513 		}
2514 	}
2515 
2516 	if (radiostat->num_channels) {
2517 		ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
2518 						      vendor_event);
2519 		if (ret)
2520 			goto failure;
2521 	}
2522 
2523 	wlan_cfg80211_vendor_cmd_reply(vendor_event);
2524 	hdd_llstats_free_radio_stats(radiostat);
2525 	return;
2526 
2527 failure:
2528 	wlan_cfg80211_vendor_free_skb(vendor_event);
2529 	hdd_llstats_free_radio_stats(radiostat);
2530 }
2531 
2532 /**
2533  * hdd_link_layer_process_radio_stats() - This function is called after
2534  * @adapter: Pointer to device adapter
2535  * @more_data: More data
2536  * @radio_stat: Pointer to stats data
2537  * @num_radio: Number of radios
2538  *
2539  * Receiving Link Layer Radio statistics from FW.This function converts
2540  * the firmware data to the NL data and sends the same to the kernel/upper
2541  * layers.
2542  *
2543  * Return: None
2544  */
2545 static void
hdd_link_layer_process_radio_stats(struct hdd_adapter * adapter,u32 more_data,struct wifi_radio_stats * radio_stat,u32 num_radio)2546 hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
2547 				   u32 more_data,
2548 				   struct wifi_radio_stats *radio_stat,
2549 				   u32 num_radio)
2550 {
2551 	int i, nr;
2552 	struct wifi_radio_stats *radio_stat_save = radio_stat;
2553 
2554 	/*
2555 	 * There is no need for wlan_hdd_validate_context here. This is a NB
2556 	 * operation that will come with DSC synchronization. This ensures that
2557 	 * no driver transition will take place as long as this operation is
2558 	 * not complete. Thus the need to check validity of hdd_context is not
2559 	 * required.
2560 	 */
2561 
2562 	for (i = 0; i < num_radio; i++) {
2563 		hdd_nofl_debug("LL_STATS_RADIO"
2564 		       " radio: %u on_time: %u tx_time: %u rx_time: %u"
2565 		       " on_time_scan: %u on_time_nbd: %u"
2566 		       " on_time_gscan: %u on_time_roam_scan: %u"
2567 		       " on_time_pno_scan: %u  on_time_hs20: %u"
2568 		       " num_channels: %u total_num_tx_pwr_levels: %u"
2569 		       " on_time_host_scan: %u, on_time_lpi_scan: %u",
2570 		       radio_stat->radio, radio_stat->on_time,
2571 		       radio_stat->tx_time, radio_stat->rx_time,
2572 		       radio_stat->on_time_scan, radio_stat->on_time_nbd,
2573 		       radio_stat->on_time_gscan,
2574 		       radio_stat->on_time_roam_scan,
2575 		       radio_stat->on_time_pno_scan,
2576 		       radio_stat->on_time_hs20,
2577 		       radio_stat->num_channels,
2578 		       radio_stat->total_num_tx_power_levels,
2579 		       radio_stat->on_time_host_scan,
2580 		       radio_stat->on_time_lpi_scan);
2581 		radio_stat++;
2582 	}
2583 
2584 	radio_stat = radio_stat_save;
2585 	for (nr = 0; nr < num_radio; nr++) {
2586 		hdd_llstats_post_radio_stats(adapter, more_data,
2587 					     radio_stat, num_radio);
2588 		radio_stat++;
2589 	}
2590 
2591 	hdd_exit();
2592 }
2593 
hdd_process_ll_stats(tSirLLStatsResults * results,struct osif_request * request)2594 static void hdd_process_ll_stats(tSirLLStatsResults *results,
2595 				 struct osif_request *request)
2596 {
2597 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2598 	struct hdd_ll_stats *stats = NULL;
2599 	size_t stat_size = 0;
2600 
2601 	qdf_spin_lock(&priv->ll_stats_lock);
2602 
2603 	if (!(priv->request_bitmap & results->paramId)) {
2604 		qdf_spin_unlock(&priv->ll_stats_lock);
2605 		return;
2606 	}
2607 
2608 	if (results->paramId & WMI_LINK_STATS_RADIO) {
2609 		struct wifi_radio_stats *rs_results, *stat_result;
2610 		u64 channel_size = 0, pwr_lvl_size = 0;
2611 		int i;
2612 
2613 		if (!results->num_radio)
2614 			goto exit;
2615 
2616 		stats = qdf_mem_malloc(sizeof(*stats));
2617 		if (!stats)
2618 			goto exit;
2619 
2620 		stat_size = sizeof(struct wifi_radio_stats) *
2621 			    results->num_radio;
2622 		stats->result_param_id = WMI_LINK_STATS_RADIO;
2623 		stat_result = qdf_mem_malloc(stat_size);
2624 		if (!stat_result) {
2625 			qdf_mem_free(stats);
2626 			goto exit;
2627 		}
2628 		stats->result = stat_result;
2629 		rs_results = (struct wifi_radio_stats *)results->results;
2630 		qdf_mem_copy(stats->result, results->results, stat_size);
2631 		for (i = 0; i < results->num_radio; i++) {
2632 			channel_size = rs_results->num_channels *
2633 				       sizeof(struct wifi_channel_stats);
2634 			pwr_lvl_size = sizeof(uint32_t) *
2635 				       rs_results->total_num_tx_power_levels;
2636 
2637 			if (rs_results->total_num_tx_power_levels &&
2638 			    rs_results->tx_time_per_power_level) {
2639 				stat_result->tx_time_per_power_level =
2640 						qdf_mem_malloc(pwr_lvl_size);
2641 				if (!stat_result->tx_time_per_power_level) {
2642 					while (i-- > 0) {
2643 						stat_result--;
2644 						qdf_mem_free(stat_result->
2645 						    tx_time_per_power_level);
2646 						qdf_mem_free(stat_result->
2647 							     channels);
2648 					}
2649 					qdf_mem_free(stat_result);
2650 					qdf_mem_free(stats);
2651 					goto exit;
2652 				}
2653 			      qdf_mem_copy(stat_result->tx_time_per_power_level,
2654 					   rs_results->tx_time_per_power_level,
2655 					   pwr_lvl_size);
2656 			}
2657 			if (channel_size) {
2658 				stat_result->channels =
2659 						qdf_mem_malloc(channel_size);
2660 				if (!stat_result->channels) {
2661 					qdf_mem_free(stat_result->
2662 						     tx_time_per_power_level);
2663 					while (i-- > 0) {
2664 						stat_result--;
2665 						qdf_mem_free(stat_result->
2666 						    tx_time_per_power_level);
2667 						qdf_mem_free(stat_result->
2668 							     channels);
2669 					}
2670 					qdf_mem_free(stats->result);
2671 					qdf_mem_free(stats);
2672 					goto exit;
2673 				}
2674 				qdf_mem_copy(stat_result->channels,
2675 					     rs_results->channels,
2676 					     channel_size);
2677 			}
2678 			rs_results++;
2679 			stat_result++;
2680 		}
2681 		stats->stats_nradio_npeer.no_of_radios = results->num_radio;
2682 		stats->more_data = results->moreResultToFollow;
2683 		if (!results->moreResultToFollow)
2684 			priv->request_bitmap &= ~stats->result_param_id;
2685 	} else if (results->paramId & WMI_LINK_STATS_IFACE) {
2686 		stats = qdf_mem_malloc(sizeof(*stats));
2687 		if (!stats)
2688 			goto exit;
2689 
2690 		stats->result_param_id = WMI_LINK_STATS_IFACE;
2691 		stats->stats_nradio_npeer.no_of_peers = results->num_peers;
2692 		stats->result = qdf_mem_malloc(sizeof(struct
2693 					       wifi_interface_stats));
2694 		if (!stats->result) {
2695 			qdf_mem_free(stats);
2696 			goto exit;
2697 		}
2698 		qdf_mem_copy(stats->result, results->results,
2699 			     sizeof(struct wifi_interface_stats));
2700 
2701 		/* Firmware doesn't send peerstats event if no peers are
2702 		 * connected. HDD should not wait for any peerstats in
2703 		 * this case and return the status to middleware after
2704 		 * receiving iface stats
2705 		 */
2706 		if (!results->num_peers)
2707 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2708 		priv->request_bitmap &= ~stats->result_param_id;
2709 
2710 		/* Firmware sends interface stats based on vdev_id_bitmap
2711 		 * So, clear the mlo_vdev_id_bitmap in the host accordingly
2712 		 */
2713 		if (priv->is_mlo_req)
2714 			priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId);
2715 	} else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
2716 		struct wifi_peer_stat *peer_stat = (struct wifi_peer_stat *)
2717 						   results->results;
2718 		struct wifi_peer_info *peer_info = NULL;
2719 		u64 num_rate = 0, peers, rates;
2720 		int i;
2721 		stats = qdf_mem_malloc(sizeof(*stats));
2722 		if (!stats)
2723 			goto exit;
2724 
2725 		peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
2726 		for (i = 1; i <= peer_stat->num_peers; i++) {
2727 			num_rate += peer_info->num_rate;
2728 			peer_info = (struct wifi_peer_info *)((uint8_t *)
2729 				    peer_info + sizeof(struct wifi_peer_info) +
2730 				    (peer_info->num_rate *
2731 				    sizeof(struct wifi_rate_stat)));
2732 		}
2733 
2734 		peers = sizeof(struct wifi_peer_info) * peer_stat->num_peers;
2735 		rates = sizeof(struct wifi_rate_stat) * num_rate;
2736 		stat_size = sizeof(struct wifi_peer_stat) + peers + rates;
2737 		stats->result_param_id = WMI_LINK_STATS_ALL_PEER;
2738 
2739 		stats->result = qdf_mem_malloc(stat_size);
2740 		if (!stats->result) {
2741 			qdf_mem_free(stats);
2742 			goto exit;
2743 		}
2744 
2745 		qdf_mem_copy(stats->result, results->results, stat_size);
2746 		stats->more_data = results->moreResultToFollow;
2747 		if (!results->moreResultToFollow)
2748 			priv->request_bitmap &= ~stats->result_param_id;
2749 	} else {
2750 		hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
2751 	}
2752 	/* send indication to caller thread */
2753 	if (stats)
2754 		qdf_list_insert_back(&priv->ll_stats_q, &stats->ll_stats_node);
2755 
2756 	if (!priv->request_bitmap) {
2757 		if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap)
2758 			goto out;
2759 exit:
2760 		qdf_spin_unlock(&priv->ll_stats_lock);
2761 
2762 		/* Thread which invokes this function has allocated memory in
2763 		 * WMA for radio stats, that memory should be freed from the
2764 		 * same thread to avoid any race conditions between two threads
2765 		 */
2766 		sme_radio_tx_mem_free();
2767 		osif_request_complete(request);
2768 		return;
2769 	}
2770 out:
2771 	qdf_spin_unlock(&priv->ll_stats_lock);
2772 }
2773 
hdd_debugfs_process_ll_stats(struct wlan_hdd_link_info * link_info,tSirLLStatsResults * results,struct osif_request * request)2774 static void hdd_debugfs_process_ll_stats(struct wlan_hdd_link_info *link_info,
2775 					 tSirLLStatsResults *results,
2776 					 struct osif_request *request)
2777 {
2778 	struct hdd_adapter *adapter = link_info->adapter;
2779 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2780 
2781 	if (results->paramId & WMI_LINK_STATS_RADIO) {
2782 		hdd_debugfs_process_radio_stats(adapter,
2783 						results->moreResultToFollow,
2784 						results->results,
2785 						results->num_radio);
2786 		if (!results->moreResultToFollow)
2787 			priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
2788 	} else if (results->paramId & WMI_LINK_STATS_IFACE) {
2789 		hdd_debugfs_process_iface_stats(link_info, results->results,
2790 						results->num_peers);
2791 
2792 		/* Firmware doesn't send peerstats event if no peers are
2793 		 * connected. HDD should not wait for any peerstats in
2794 		 * this case and return the status to middleware after
2795 		 * receiving iface stats
2796 		 */
2797 
2798 		if (!results->num_peers)
2799 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2800 
2801 		priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
2802 
2803 		/* Firmware sends interface stats based on vdev_id_bitmap
2804 		 * So, clear the mlo_vdev_id_bitmap in the host accordingly
2805 		 */
2806 		if (priv->is_mlo_req)
2807 			priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId);
2808 	} else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
2809 		hdd_debugfs_process_peer_stats(adapter, results->results);
2810 		if (!results->moreResultToFollow)
2811 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2812 	} else {
2813 		hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
2814 	}
2815 
2816 	if (!priv->request_bitmap) {
2817 		if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap)
2818 			return;
2819 		/* Thread which invokes this function has allocated memory in
2820 		 * WMA for radio stats, that memory should be freed from the
2821 		 * same thread to avoid any race conditions between two threads
2822 		 */
2823 		sme_radio_tx_mem_free();
2824 		osif_request_complete(request);
2825 	}
2826 
2827 }
2828 
2829 static void
wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context * hdd_ctx,struct osif_request * request,tSirLLStatsResults * results)2830 wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context *hdd_ctx,
2831 					struct osif_request *request,
2832 					tSirLLStatsResults *results)
2833 {
2834 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2835 	bool is_mlo_link;
2836 
2837 	if (!wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc, priv->vdev_id)) {
2838 		hdd_nofl_debug("Can't update req_bitmap for non MLO case");
2839 		return;
2840 	}
2841 
2842 	is_mlo_link = wlan_vdev_mlme_get_is_mlo_link(hdd_ctx->psoc,
2843 						     results->ifaceId);
2844 	/* In case of MLO Connection, set the request_bitmap */
2845 	if (is_mlo_link && results->paramId == WMI_LINK_STATS_IFACE) {
2846 		/* Set the request_bitmap for MLO link vdev iface stats */
2847 		if (!(priv->request_bitmap & results->paramId))
2848 			priv->request_bitmap |= results->paramId;
2849 
2850 		hdd_nofl_debug("MLO_LL_STATS set request_bitmap = 0x%x",
2851 			       priv->request_bitmap);
2852 	}
2853 }
2854 
wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,int indication_type,tSirLLStatsResults * results,void * cookie)2855 void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
2856 						 int indication_type,
2857 						 tSirLLStatsResults *results,
2858 						 void *cookie)
2859 {
2860 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
2861 	struct hdd_ll_stats_priv *priv;
2862 	struct wlan_hdd_link_info *link_info;
2863 	int status;
2864 	struct osif_request *request;
2865 
2866 	status = wlan_hdd_validate_context(hdd_ctx);
2867 	if (status)
2868 		return;
2869 
2870 	switch (indication_type) {
2871 	case SIR_HAL_LL_STATS_RESULTS_RSP:
2872 	{
2873 		hdd_nofl_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK",
2874 			       results->paramId, results->ifaceId,
2875 			       results->rspId, results->moreResultToFollow,
2876 			       results->num_radio, results->results);
2877 
2878 		request = osif_request_get(cookie);
2879 		if (!request) {
2880 			hdd_err("Obsolete request");
2881 			return;
2882 		}
2883 
2884 		priv = osif_request_priv(request);
2885 
2886 		/* validate response received from target */
2887 		if (priv->request_id != results->rspId) {
2888 			hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
2889 				priv->request_id, results->rspId,
2890 				priv->request_bitmap, results->paramId);
2891 			osif_request_put(request);
2892 			return;
2893 		}
2894 
2895 		link_info =
2896 			hdd_get_link_info_by_vdev(hdd_ctx, results->ifaceId);
2897 		if (!link_info) {
2898 			hdd_debug_rl("invalid vdev_id %d sent by FW",
2899 				     results->ifaceId);
2900 			/* for peer stats FW doesn't update the vdev_id info*/
2901 			link_info = hdd_get_link_info_by_vdev(hdd_ctx,
2902 							      priv->vdev_id);
2903 			if (!link_info) {
2904 				hdd_err("invalid vdev %d", priv->vdev_id);
2905 				osif_request_put(request);
2906 				return;
2907 			}
2908 		}
2909 		wlan_hdd_update_ll_stats_request_bitmap(hdd_ctx, request,
2910 							results);
2911 		if (results->rspId == DEBUGFS_LLSTATS_REQID) {
2912 			hdd_debugfs_process_ll_stats(link_info,
2913 						     results, request);
2914 		 } else {
2915 			hdd_process_ll_stats(results, request);
2916 		}
2917 
2918 		osif_request_put(request);
2919 		break;
2920 	}
2921 	default:
2922 		hdd_warn("invalid event type %d", indication_type);
2923 		break;
2924 	}
2925 }
2926 
hdd_lost_link_info_cb(hdd_handle_t hdd_handle,struct sir_lost_link_info * lost_link_info)2927 void hdd_lost_link_info_cb(hdd_handle_t hdd_handle,
2928 			   struct sir_lost_link_info *lost_link_info)
2929 {
2930 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
2931 	int status;
2932 	struct wlan_hdd_link_info *link_info;
2933 	struct hdd_station_ctx *sta_ctx;
2934 
2935 	status = wlan_hdd_validate_context(hdd_ctx);
2936 	if (status)
2937 		return;
2938 
2939 	if (!lost_link_info) {
2940 		hdd_err("lost_link_info is NULL");
2941 		return;
2942 	}
2943 
2944 	if (lost_link_info->rssi == 0) {
2945 		hdd_debug_rl("Invalid rssi on disconnect sent by FW");
2946 		return;
2947 	}
2948 
2949 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, lost_link_info->vdev_id);
2950 	if (!link_info) {
2951 		hdd_err("invalid vdev");
2952 		return;
2953 	}
2954 
2955 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2956 
2957 	link_info->rssi_on_disconnect = lost_link_info->rssi;
2958 	hdd_debug("rssi on disconnect %d", link_info->rssi_on_disconnect);
2959 
2960 	sta_ctx->cache_conn_info.signal = lost_link_info->rssi;
2961 }
2962 
2963 const struct nla_policy qca_wlan_vendor_ll_set_policy[
2964 			QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
2965 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]
2966 						= { .type = NLA_U32 },
2967 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]
2968 						= { .type = NLA_U32 },
2969 };
2970 
2971 /**
2972  * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
2973  * @wiphy: Pointer to wiphy
2974  * @wdev: Pointer to wdev
2975  * @data: Pointer to data
2976  * @data_len: Data length
2977  *
2978  * Return: int
2979  */
2980 static int
__wlan_hdd_cfg80211_ll_stats_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2981 __wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
2982 				   struct wireless_dev *wdev,
2983 				   const void *data,
2984 				   int data_len)
2985 {
2986 	int status;
2987 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
2988 	tSirLLStatsSetReq req;
2989 	struct net_device *dev = wdev->netdev;
2990 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2991 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2992 
2993 	hdd_enter_dev(dev);
2994 
2995 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2996 		hdd_err("Command not allowed in FTM mode");
2997 		return -EPERM;
2998 	}
2999 
3000 	status = wlan_hdd_validate_context(hdd_ctx);
3001 	if (0 != status)
3002 		return -EINVAL;
3003 
3004 	if (hdd_validate_adapter(adapter))
3005 		return -EINVAL;
3006 
3007 	if (adapter->device_mode != QDF_STA_MODE &&
3008 	    adapter->device_mode != QDF_SAP_MODE &&
3009 	    adapter->device_mode != QDF_P2P_CLIENT_MODE &&
3010 	    adapter->device_mode != QDF_P2P_GO_MODE) {
3011 		hdd_debug("Cannot set LL_STATS for device mode %d",
3012 			  adapter->device_mode);
3013 		return -EINVAL;
3014 	}
3015 
3016 	if (wlan_cfg80211_nla_parse(tb_vendor,
3017 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
3018 				    (struct nlattr *)data, data_len,
3019 				    qca_wlan_vendor_ll_set_policy)) {
3020 		hdd_err("maximum attribute not present");
3021 		return -EINVAL;
3022 	}
3023 
3024 	if (!tb_vendor
3025 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
3026 		hdd_err("MPDU size Not present");
3027 		return -EINVAL;
3028 	}
3029 
3030 	if (!tb_vendor
3031 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
3032 		hdd_err("Stats Gathering Not Present");
3033 		return -EINVAL;
3034 	}
3035 
3036 	/* Shall take the request Id if the Upper layers pass. 1 For now. */
3037 	req.reqId = 1;
3038 
3039 	req.mpduSizeThreshold =
3040 		nla_get_u32(tb_vendor
3041 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
3042 
3043 	req.aggressiveStatisticsGathering =
3044 		nla_get_u32(tb_vendor
3045 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
3046 
3047 	req.staId = adapter->deflink->vdev_id;
3048 
3049 	hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
3050 		req.reqId, req.staId,
3051 		req.mpduSizeThreshold,
3052 		req.aggressiveStatisticsGathering);
3053 
3054 	if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->mac_handle,
3055 						       &req)) {
3056 		hdd_err("sme_ll_stats_set_req Failed");
3057 		return -EINVAL;
3058 	}
3059 
3060 	adapter->is_link_layer_stats_set = true;
3061 	hdd_exit();
3062 	return 0;
3063 }
3064 
3065 /**
3066  * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
3067  * @wiphy: Pointer to wiphy
3068  * @wdev: Pointer to wdev
3069  * @data: Pointer to data
3070  * @data_len: Data length
3071  *
3072  * Return: 0 if success, non-zero for failure
3073  */
wlan_hdd_cfg80211_ll_stats_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3074 int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
3075 					struct wireless_dev *wdev,
3076 					const void *data,
3077 					int data_len)
3078 {
3079 	int errno;
3080 	struct osif_vdev_sync *vdev_sync;
3081 
3082 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3083 	if (errno)
3084 		return errno;
3085 
3086 	errno = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
3087 
3088 	osif_vdev_sync_op_stop(vdev_sync);
3089 
3090 	return errno;
3091 }
3092 
3093 const struct nla_policy qca_wlan_vendor_ll_get_policy[
3094 			QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
3095 	/* Unsigned 32bit value provided by the caller issuing the GET stats
3096 	 * command. When reporting
3097 	 * the stats results, the driver uses the same value to indicate
3098 	 * which GET request the results
3099 	 * correspond to.
3100 	 */
3101 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
3102 
3103 	/* Unsigned 32bit value . bit mask to identify what statistics are
3104 	 * requested for retrieval
3105 	 */
3106 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
3107 };
3108 
wlan_hdd_handle_ll_stats(struct wlan_hdd_link_info * link_info,struct hdd_ll_stats * stats,int ret)3109 static void wlan_hdd_handle_ll_stats(struct wlan_hdd_link_info *link_info,
3110 				     struct hdd_ll_stats *stats, int ret)
3111 {
3112 	struct hdd_adapter *adapter = link_info->adapter;
3113 
3114 	switch (stats->result_param_id) {
3115 	case WMI_LINK_STATS_RADIO:
3116 	{
3117 		struct wifi_radio_stats *radio_stat = stats->result;
3118 		int i, num_radio = stats->stats_nradio_npeer.no_of_radios;
3119 
3120 		if (ret == -ETIMEDOUT) {
3121 			for (i = 0; i < num_radio; i++) {
3122 				if (radio_stat->num_channels)
3123 					qdf_mem_free(radio_stat->channels);
3124 				if (radio_stat->total_num_tx_power_levels)
3125 					qdf_mem_free(radio_stat->
3126 						     tx_time_per_power_level);
3127 				radio_stat++;
3128 			}
3129 			return;
3130 		}
3131 		hdd_link_layer_process_radio_stats(adapter, stats->more_data,
3132 						   radio_stat, num_radio);
3133 	}
3134 		break;
3135 	case WMI_LINK_STATS_IFACE:
3136 		hdd_link_layer_process_iface_stats(link_info,
3137 						   stats->result,
3138 						   stats->stats_nradio_npeer.
3139 						   no_of_peers);
3140 		break;
3141 	case WMI_LINK_STATS_ALL_PEER:
3142 		hdd_link_layer_process_peer_stats(adapter,
3143 						  stats->more_data,
3144 						  stats->result);
3145 		break;
3146 	default:
3147 		hdd_err("not requested event");
3148 	}
3149 }
3150 
wlan_hdd_dealloc_ll_stats(void * priv)3151 static void wlan_hdd_dealloc_ll_stats(void *priv)
3152 {
3153 	struct hdd_ll_stats_priv *ll_stats_priv = priv;
3154 	struct hdd_ll_stats *stats = NULL;
3155 	QDF_STATUS status;
3156 	qdf_list_node_t *ll_node;
3157 
3158 	if (!ll_stats_priv)
3159 		return;
3160 
3161 	qdf_spin_lock(&ll_stats_priv->ll_stats_lock);
3162 	status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q, &ll_node);
3163 	qdf_spin_unlock(&ll_stats_priv->ll_stats_lock);
3164 	while (QDF_IS_STATUS_SUCCESS(status)) {
3165 		stats =  qdf_container_of(ll_node, struct hdd_ll_stats,
3166 					  ll_stats_node);
3167 
3168 		if (stats->result_param_id == WMI_LINK_STATS_RADIO) {
3169 			struct wifi_radio_stats *radio_stat = stats->result;
3170 			int i;
3171 			int num_radio = stats->stats_nradio_npeer.no_of_radios;
3172 
3173 			for (i = 0; i < num_radio; i++) {
3174 				if (radio_stat->num_channels)
3175 					qdf_mem_free(radio_stat->channels);
3176 				if (radio_stat->total_num_tx_power_levels)
3177 					qdf_mem_free(radio_stat->
3178 						tx_time_per_power_level);
3179 				radio_stat++;
3180 			}
3181 		}
3182 
3183 		qdf_mem_free(stats->result);
3184 		qdf_mem_free(stats);
3185 		qdf_spin_lock(&ll_stats_priv->ll_stats_lock);
3186 		status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q,
3187 					       &ll_node);
3188 		qdf_spin_unlock(&ll_stats_priv->ll_stats_lock);
3189 	}
3190 	qdf_list_destroy(&ll_stats_priv->ll_stats_q);
3191 }
3192 
3193 static QDF_STATUS
wlan_hdd_set_ll_stats_request_pending(struct hdd_adapter * adapter)3194 wlan_hdd_set_ll_stats_request_pending(struct hdd_adapter *adapter)
3195 {
3196 	if (qdf_atomic_read(&adapter->is_ll_stats_req_pending)) {
3197 		hdd_nofl_debug("Previous ll_stats request is in progress");
3198 		return QDF_STATUS_E_ALREADY;
3199 	}
3200 
3201 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 1);
3202 	return QDF_STATUS_SUCCESS;
3203 }
3204 
3205 #ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
3206 /**
3207  * cache_station_stats_cb() - cache_station_stats_cb callback function
3208  * @ev: station stats buffer
3209  * @cookie: cookie that contains the address of the adapter corresponding to
3210  *          the request
3211  *
3212  * Return: None
3213  */
cache_station_stats_cb(struct stats_event * ev,void * cookie)3214 static void cache_station_stats_cb(struct stats_event *ev, void *cookie)
3215 {
3216 	struct hdd_adapter *adapter = cookie, *next_adapter = NULL;
3217 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
3218 	uint8_t vdev_id;
3219 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DISPLAY_TXRX_STATS;
3220 	struct wlan_hdd_link_info *link_info;
3221 
3222 	if (!ev->vdev_summary_stats || !ev->vdev_chain_rssi ||
3223 	    !ev->peer_adv_stats || !ev->pdev_stats) {
3224 		hdd_debug("Invalid stats");
3225 		return;
3226 	}
3227 
3228 	vdev_id = ev->vdev_summary_stats->vdev_id;
3229 
3230 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
3231 					   dbgid) {
3232 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
3233 			if (link_info->vdev_id != vdev_id)
3234 				continue;
3235 
3236 			copy_station_stats_to_adapter(link_info, ev);
3237 			wlan_hdd_get_peer_rx_rate_stats(link_info);
3238 
3239 			/* dev_put has to be done here */
3240 			hdd_adapter_dev_put_debug(adapter, dbgid);
3241 			if (next_adapter)
3242 				hdd_adapter_dev_put_debug(next_adapter, dbgid);
3243 			return;
3244 		}
3245 		hdd_adapter_dev_put_debug(adapter, dbgid);
3246 	}
3247 }
3248 
3249 #ifdef WLAN_FEATURE_11BE_MLO
3250 static QDF_STATUS
wlan_hdd_get_mlo_vdev_params(struct hdd_adapter * adapter,struct request_info * req_info,tSirLLStatsGetReq * req)3251 wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
3252 			     struct request_info *req_info,
3253 			     tSirLLStatsGetReq *req)
3254 {
3255 	struct wlan_objmgr_peer *peer;
3256 	struct wlan_objmgr_vdev *vdev;
3257 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
3258 	struct mlo_stats_vdev_params *info = &req_info->ml_vdev_info;
3259 	int i;
3260 	uint32_t bmap = 0;
3261 	QDF_STATUS status;
3262 
3263 	req->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(
3264 					psoc, adapter->deflink->vdev_id);
3265 	status = mlo_get_mlstats_vdev_params(psoc, info,
3266 					     adapter->deflink->vdev_id);
3267 	if (QDF_IS_STATUS_ERROR(status))
3268 		return status;
3269 	for (i = 0; i < info->ml_vdev_count; i++) {
3270 		bmap |= (1 << info->ml_vdev_id[i]);
3271 
3272 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
3273 							    info->ml_vdev_id[i],
3274 							    WLAN_OSIF_STATS_ID);
3275 		if (!vdev) {
3276 			hdd_err("vdev object is NULL for vdev %d",
3277 				info->ml_vdev_id[i]);
3278 			return QDF_STATUS_E_INVAL;
3279 		}
3280 
3281 		peer = wlan_objmgr_vdev_try_get_bsspeer(vdev,
3282 							WLAN_OSIF_STATS_ID);
3283 		if (!peer) {
3284 			hdd_err("peer is null");
3285 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3286 			return QDF_STATUS_E_INVAL;
3287 		}
3288 
3289 		qdf_mem_copy(&(req_info->ml_peer_mac_addr[i][0]), peer->macaddr,
3290 			     QDF_MAC_ADDR_SIZE);
3291 
3292 		wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID);
3293 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3294 	}
3295 	req->mlo_vdev_id_bitmap = bmap;
3296 	return QDF_STATUS_SUCCESS;
3297 }
3298 #else
3299 static QDF_STATUS
wlan_hdd_get_mlo_vdev_params(struct hdd_adapter * adapter,struct request_info * req_info,tSirLLStatsGetReq * req)3300 wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
3301 			     struct request_info *req_info,
3302 			     tSirLLStatsGetReq *req)
3303 {
3304 	return QDF_STATUS_SUCCESS;
3305 }
3306 #endif
3307 
3308 static QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info * link_info,tSirLLStatsGetReq * req)3309 wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info,
3310 					   tSirLLStatsGetReq *req)
3311 {
3312 	struct wlan_objmgr_peer *peer;
3313 	struct request_info info = {0};
3314 	struct wlan_objmgr_vdev *vdev;
3315 	struct hdd_adapter *adapter = link_info->adapter;
3316 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
3317 	bool is_mlo_vdev = false;
3318 	QDF_STATUS status;
3319 
3320 	if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
3321 		return QDF_STATUS_E_INVAL;
3322 
3323 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
3324 	if (!vdev)
3325 		return QDF_STATUS_E_INVAL;
3326 
3327 	info.cookie = adapter;
3328 	info.u.get_station_stats_cb = cache_station_stats_cb;
3329 	info.vdev_id = link_info->vdev_id;
3330 	is_mlo_vdev = wlan_vdev_mlme_get_is_mlo_vdev(psoc, link_info->vdev_id);
3331 	if (is_mlo_vdev) {
3332 		status = wlan_hdd_get_mlo_vdev_params(adapter, &info, req);
3333 		if (QDF_IS_STATUS_ERROR(status)) {
3334 			hdd_err("unable to get vdev params for mlo stats");
3335 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3336 			return status;
3337 		}
3338 	}
3339 
3340 	info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
3341 
3342 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_STATS_ID);
3343 	if (!peer) {
3344 		osif_err("peer is null");
3345 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3346 		return QDF_STATUS_E_INVAL;
3347 	}
3348 
3349 	qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE);
3350 
3351 	wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID);
3352 
3353 	ucfg_mc_cp_stats_set_pending_req(psoc, TYPE_STATION_STATS, &info);
3354 
3355 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3356 	return QDF_STATUS_SUCCESS;
3357 }
3358 
3359 static void
wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc * psoc,struct hdd_adapter * adapter)3360 wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
3361 					     struct hdd_adapter *adapter)
3362 {
3363 	QDF_STATUS status;
3364 	struct request_info last_req = {0};
3365 	bool pending = false;
3366 
3367 	if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
3368 		return;
3369 
3370 	status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS,
3371 						  &last_req);
3372 	if (QDF_IS_STATUS_ERROR(status)) {
3373 		hdd_err("ucfg_mc_cp_stats_get_pending_req failed");
3374 		return;
3375 	}
3376 
3377 	ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS,
3378 					   &last_req, &pending);
3379 }
3380 
wlan_hdd_stats_request_needed(struct hdd_adapter * adapter)3381 static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
3382 {
3383 	if (adapter->device_mode != QDF_STA_MODE)
3384 		return QDF_STATUS_SUCCESS;
3385 
3386 	if (!adapter->hdd_ctx->config) {
3387 		hdd_err("Invalid hdd config");
3388 		return QDF_STATUS_E_INVAL;
3389 	}
3390 
3391 	if (adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) {
3392 		uint32_t stats_cached_duration;
3393 
3394 		stats_cached_duration =
3395 				qdf_system_ticks_to_msecs(qdf_system_ticks()) -
3396 				adapter->sta_stats_cached_timestamp;
3397 		if (qdf_atomic_read(&adapter->is_ll_stats_req_pending) ||
3398 		    (stats_cached_duration <=
3399 			adapter->hdd_ctx->config->sta_stats_cache_expiry_time))
3400 			return QDF_STATUS_E_ALREADY;
3401 	}
3402 
3403 	return QDF_STATUS_SUCCESS;
3404 }
3405 
3406 #else
3407 static inline QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info * link_info,tSirLLStatsGetReq * req)3408 wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info,
3409 					   tSirLLStatsGetReq *req)
3410 {
3411 	return QDF_STATUS_SUCCESS;
3412 }
3413 
3414 static void
wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc * psoc,struct hdd_adapter * adapter)3415 wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
3416 					     struct hdd_adapter *adapter)
3417 {
3418 }
3419 
wlan_hdd_stats_request_needed(struct hdd_adapter * adapter)3420 static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
3421 {
3422 	return QDF_STATUS_SUCCESS;
3423 }
3424 #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
3425 
wlan_hdd_send_mlo_ll_stats_to_user(struct hdd_adapter * adapter)3426 static void wlan_hdd_send_mlo_ll_stats_to_user(struct hdd_adapter *adapter)
3427 {
3428 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
3429 		return;
3430 
3431 	wlan_hdd_send_mlo_ll_iface_stats_to_user(adapter);
3432 	wlan_hdd_send_mlo_ll_peer_stats_to_user(adapter);
3433 }
3434 
wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info * link_info,tSirLLStatsGetReq * req)3435 static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
3436 				      tSirLLStatsGetReq *req)
3437 {
3438 	int ret = 0;
3439 	struct hdd_ll_stats_priv *priv;
3440 	struct hdd_ll_stats *stats = NULL;
3441 	struct osif_request *request;
3442 	qdf_list_node_t *ll_node;
3443 	QDF_STATUS status, vdev_req_status;
3444 	struct hdd_adapter *adapter = link_info->adapter;
3445 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3446 	void *cookie;
3447 	static const struct osif_request_params params = {
3448 		.priv_size = sizeof(*priv),
3449 		.timeout_ms = WLAN_WAIT_TIME_LL_STATS,
3450 		.dealloc = wlan_hdd_dealloc_ll_stats,
3451 	};
3452 
3453 	hdd_enter_dev(adapter->dev);
3454 
3455 	status = wlan_hdd_set_ll_stats_request_pending(adapter);
3456 	if (QDF_IS_STATUS_ERROR(status))
3457 		return qdf_status_to_os_return(status);
3458 
3459 	vdev_req_status = wlan_hdd_set_station_stats_request_pending(link_info,
3460 								     req);
3461 	if (QDF_IS_STATUS_ERROR(vdev_req_status))
3462 		hdd_nofl_debug("Requesting LL_STATS only");
3463 
3464 	/*
3465 	 * FW can send radio stats with multiple events and for the first event
3466 	 * host allocates memory in wma and processes the events, there is a
3467 	 * possibility that host receives first event and gets timed out, on
3468 	 * time out host frees the allocated memory. now if host receives
3469 	 * remaining events it will again allocate memory and processes the
3470 	 * stats, since this is not an allocation for new command, this will
3471 	 * lead to out of order processing of the next event and this memory
3472 	 * might not be freed, so free the already allocated memory from WMA
3473 	 * before issuing any new ll stats request free memory allocated for
3474 	 * previous command
3475 	 */
3476 	sme_radio_tx_mem_free();
3477 
3478 	request = osif_request_alloc(&params);
3479 	if (!request) {
3480 		hdd_err("Request Allocation Failure");
3481 		wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc,
3482 							     adapter);
3483 		return -ENOMEM;
3484 	}
3485 
3486 	cookie = osif_request_cookie(request);
3487 
3488 	priv = osif_request_priv(request);
3489 
3490 	priv->request_id = req->reqId;
3491 	priv->request_bitmap = req->paramIdMask;
3492 	priv->vdev_id = link_info->vdev_id;
3493 	priv->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc,
3494 							  link_info->vdev_id);
3495 	if (priv->is_mlo_req)
3496 		priv->mlo_vdev_id_bitmap = req->mlo_vdev_id_bitmap;
3497 
3498 	qdf_spinlock_create(&priv->ll_stats_lock);
3499 	qdf_list_create(&priv->ll_stats_q, HDD_LINK_STATS_MAX);
3500 
3501 	status = sme_ll_stats_get_req(hdd_ctx->mac_handle, req, cookie);
3502 	if (QDF_IS_STATUS_ERROR(status)) {
3503 		hdd_err("sme_ll_stats_get_req Failed");
3504 		ret = qdf_status_to_os_return(status);
3505 		goto exit;
3506 	}
3507 	ret = osif_request_wait_for_response(request);
3508 	if (ret) {
3509 		adapter->ll_stats_failure_count++;
3510 		hdd_err("Target response timed out request id %d request bitmap 0x%x ll_stats failure count %d",
3511 			priv->request_id, priv->request_bitmap,
3512 			adapter->ll_stats_failure_count);
3513 		qdf_spin_lock(&priv->ll_stats_lock);
3514 		priv->request_bitmap = 0;
3515 		qdf_spin_unlock(&priv->ll_stats_lock);
3516 		sme_radio_tx_mem_free();
3517 		ret = -ETIMEDOUT;
3518 	} else {
3519 		if (QDF_IS_STATUS_SUCCESS(vdev_req_status)) {
3520 			hdd_update_station_stats_cached_timestamp(adapter);
3521 			hdd_update_link_state_cached_timestamp(adapter);
3522 		}
3523 
3524 		adapter->ll_stats_failure_count = 0;
3525 	}
3526 
3527 	qdf_spin_lock(&priv->ll_stats_lock);
3528 	status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
3529 	qdf_spin_unlock(&priv->ll_stats_lock);
3530 	while (QDF_IS_STATUS_SUCCESS(status)) {
3531 		stats =  qdf_container_of(ll_node, struct hdd_ll_stats,
3532 					  ll_stats_node);
3533 		wlan_hdd_handle_ll_stats(link_info, stats, ret);
3534 		qdf_mem_free(stats->result);
3535 		qdf_mem_free(stats);
3536 		qdf_spin_lock(&priv->ll_stats_lock);
3537 		status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
3538 		qdf_spin_unlock(&priv->ll_stats_lock);
3539 	}
3540 	qdf_list_destroy(&priv->ll_stats_q);
3541 
3542 	if (!ret && req->reqId != DEBUGFS_LLSTATS_REQID)
3543 		wlan_hdd_send_mlo_ll_stats_to_user(adapter);
3544 
3545 exit:
3546 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 0);
3547 	wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc, adapter);
3548 	hdd_exit();
3549 	osif_request_put(request);
3550 
3551 	if (adapter->ll_stats_failure_count >=
3552 					HDD_MAX_ALLOWED_LL_STATS_FAILURE) {
3553 		cds_trigger_recovery(QDF_STATS_REQ_TIMEDOUT);
3554 		adapter->ll_stats_failure_count = 0;
3555 	}
3556 
3557 	return ret;
3558 }
3559 
wlan_hdd_ll_stats_get(struct wlan_hdd_link_info * link_info,uint32_t req_id,uint32_t req_mask)3560 int wlan_hdd_ll_stats_get(struct wlan_hdd_link_info *link_info,
3561 			  uint32_t req_id, uint32_t req_mask)
3562 {
3563 	int errno;
3564 	tSirLLStatsGetReq get_req;
3565 	struct hdd_adapter *adapter = link_info->adapter;
3566 
3567 	hdd_enter_dev(adapter->dev);
3568 
3569 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3570 		hdd_warn("Command not allowed in FTM mode");
3571 		return -EPERM;
3572 	}
3573 
3574 	if (hdd_cm_is_vdev_roaming(link_info)) {
3575 		hdd_debug("Roaming in progress, cannot process the request");
3576 		return -EBUSY;
3577 	}
3578 
3579 	if (!adapter->is_link_layer_stats_set) {
3580 		hdd_info("LL_STATs not set");
3581 		return -EINVAL;
3582 	}
3583 
3584 	get_req.reqId = req_id;
3585 	get_req.paramIdMask = req_mask;
3586 	get_req.staId = link_info->vdev_id;
3587 
3588 	rtnl_lock();
3589 	errno = wlan_hdd_send_ll_stats_req(link_info, &get_req);
3590 	rtnl_unlock();
3591 	if (errno)
3592 		hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
3593 			req_id, req_mask, link_info->vdev_id);
3594 
3595 	hdd_exit();
3596 
3597 	return errno;
3598 }
3599 
3600 /**
3601  * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
3602  * @wiphy: Pointer to wiphy
3603  * @wdev: Pointer to wdev
3604  * @data: Pointer to data
3605  * @data_len: Data length
3606  *
3607  * Return: int
3608  */
3609 static int
__wlan_hdd_cfg80211_ll_stats_get(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3610 __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
3611 				   struct wireless_dev *wdev,
3612 				   const void *data,
3613 				   int data_len)
3614 {
3615 	int ret;
3616 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3617 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
3618 	tSirLLStatsGetReq LinkLayerStatsGetReq;
3619 	struct net_device *dev = wdev->netdev;
3620 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3621 	struct wlan_hdd_link_info *link_info = adapter->deflink;
3622 
3623 	hdd_enter_dev(dev);
3624 
3625 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3626 		hdd_err("Command not allowed in FTM mode");
3627 		return -EPERM;
3628 	}
3629 
3630 	ret = wlan_hdd_validate_context(hdd_ctx);
3631 	if (0 != ret)
3632 		return -EINVAL;
3633 
3634 	if (!adapter->is_link_layer_stats_set) {
3635 		hdd_nofl_debug("is_link_layer_stats_set: %d",
3636 			       adapter->is_link_layer_stats_set);
3637 		return -EINVAL;
3638 	}
3639 
3640 	if (hdd_cm_is_vdev_roaming(link_info)) {
3641 		hdd_debug("Roaming in progress, cannot process the request");
3642 		return -EBUSY;
3643 	}
3644 
3645 	if (wlan_hdd_is_link_switch_in_progress(link_info)) {
3646 		hdd_debug("Link Switch in progress, can't process the request");
3647 		return -EBUSY;
3648 	}
3649 
3650 	if (wlan_cfg80211_nla_parse(tb_vendor,
3651 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
3652 				    (struct nlattr *)data, data_len,
3653 				    qca_wlan_vendor_ll_get_policy)) {
3654 		hdd_err("max attribute not present");
3655 		return -EINVAL;
3656 	}
3657 
3658 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
3659 		hdd_err("Request Id Not present");
3660 		return -EINVAL;
3661 	}
3662 
3663 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
3664 		hdd_err("Req Mask Not present");
3665 		return -EINVAL;
3666 	}
3667 
3668 	LinkLayerStatsGetReq.reqId =
3669 		nla_get_u32(tb_vendor
3670 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
3671 	LinkLayerStatsGetReq.paramIdMask =
3672 		nla_get_u32(tb_vendor
3673 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
3674 
3675 	LinkLayerStatsGetReq.staId = link_info->vdev_id;
3676 
3677 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
3678 		return -EINVAL;
3679 
3680 	ret = wlan_hdd_send_ll_stats_req(link_info, &LinkLayerStatsGetReq);
3681 	if (0 != ret) {
3682 		hdd_err("Failed to send LL stats request (id:%u)",
3683 			LinkLayerStatsGetReq.reqId);
3684 		return ret;
3685 	}
3686 
3687 	hdd_exit();
3688 	return 0;
3689 }
3690 
3691 /**
3692  * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
3693  * @wiphy: Pointer to wiphy
3694  * @wdev: Pointer to wdev
3695  * @data: Pointer to data
3696  * @data_len: Data length
3697  *
3698  * Return: 0 if success, non-zero for failure
3699  */
wlan_hdd_cfg80211_ll_stats_get(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3700 int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
3701 				   struct wireless_dev *wdev,
3702 				   const void *data,
3703 				   int data_len)
3704 {
3705 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3706 	struct osif_vdev_sync *vdev_sync;
3707 	int errno;
3708 
3709 	errno = wlan_hdd_validate_context(hdd_ctx);
3710 	if (0 != errno)
3711 		return -EINVAL;
3712 
3713 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3714 	if (errno)
3715 		return errno;
3716 
3717 	errno = wlan_hdd_qmi_get_sync_resume();
3718 	if (errno) {
3719 		hdd_err("qmi sync resume failed: %d", errno);
3720 		goto end;
3721 	}
3722 
3723 	errno = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
3724 
3725 	wlan_hdd_qmi_put_suspend();
3726 
3727 end:
3728 	osif_vdev_sync_op_stop(vdev_sync);
3729 
3730 	return errno;
3731 }
3732 
3733 const struct
3734 nla_policy
3735 	qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
3736 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
3737 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
3738 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
3739 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
3740 };
3741 
3742 /**
3743  * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
3744  * @wiphy: Pointer to wiphy
3745  * @wdev: Pointer to wdev
3746  * @data: Pointer to data
3747  * @data_len: Data length
3748  *
3749  * Return: int
3750  */
3751 static int
__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3752 __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
3753 				    struct wireless_dev *wdev,
3754 				    const void *data,
3755 				    int data_len)
3756 {
3757 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3758 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
3759 	tSirLLStatsClearReq LinkLayerStatsClearReq;
3760 	struct net_device *dev = wdev->netdev;
3761 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3762 	u32 statsClearReqMask;
3763 	u8 stopReq;
3764 	int errno;
3765 	QDF_STATUS status;
3766 	struct sk_buff *skb;
3767 
3768 	hdd_enter_dev(dev);
3769 
3770 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3771 		hdd_err("Command not allowed in FTM mode");
3772 		return -EPERM;
3773 	}
3774 
3775 	errno = wlan_hdd_validate_context(hdd_ctx);
3776 	if (errno)
3777 		return -EINVAL;
3778 
3779 	if (!adapter->is_link_layer_stats_set) {
3780 		hdd_warn("is_link_layer_stats_set : %d",
3781 			  adapter->is_link_layer_stats_set);
3782 		return -EINVAL;
3783 	}
3784 
3785 	if (wlan_cfg80211_nla_parse(tb_vendor,
3786 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
3787 				    (struct nlattr *)data, data_len,
3788 				    qca_wlan_vendor_ll_clr_policy)) {
3789 		hdd_err("STATS_CLR_MAX is not present");
3790 		return -EINVAL;
3791 	}
3792 
3793 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
3794 	    !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
3795 		hdd_err("Error in LL_STATS CLR CONFIG PARA");
3796 		return -EINVAL;
3797 	}
3798 
3799 	statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
3800 				    nla_get_u32(tb_vendor
3801 						[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
3802 
3803 	stopReq = LinkLayerStatsClearReq.stopReq =
3804 			  nla_get_u8(tb_vendor
3805 				     [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
3806 
3807 	/*
3808 	 * Shall take the request Id if the Upper layers pass. 1 For now.
3809 	 */
3810 	LinkLayerStatsClearReq.reqId = 1;
3811 
3812 	LinkLayerStatsClearReq.staId = adapter->deflink->vdev_id;
3813 
3814 	hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
3815 		LinkLayerStatsClearReq.reqId,
3816 		LinkLayerStatsClearReq.staId,
3817 		LinkLayerStatsClearReq.statsClearReqMask,
3818 		LinkLayerStatsClearReq.stopReq);
3819 
3820 	status = sme_ll_stats_clear_req(hdd_ctx->mac_handle,
3821 					&LinkLayerStatsClearReq);
3822 	if (QDF_IS_STATUS_ERROR(status)) {
3823 		hdd_err("stats clear request failed, %d", status);
3824 		return -EINVAL;
3825 	}
3826 
3827 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
3828 						       2 * sizeof(u32) +
3829 						       2 * NLMSG_HDRLEN);
3830 	if (!skb) {
3831 		hdd_err("skb allocation failed");
3832 		return -ENOMEM;
3833 	}
3834 
3835 	if (nla_put_u32(skb,
3836 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
3837 			statsClearReqMask) ||
3838 	    nla_put_u32(skb,
3839 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
3840 			stopReq)) {
3841 		hdd_err("LL_STATS_CLR put fail");
3842 		wlan_cfg80211_vendor_free_skb(skb);
3843 		return -EINVAL;
3844 	}
3845 
3846 	/* If the ask is to stop the stats collection
3847 	 * as part of clear (stopReq = 1), ensure
3848 	 * that no further requests of get go to the
3849 	 * firmware by having is_link_layer_stats_set set
3850 	 * to 0.  However it the stopReq as part of
3851 	 * the clear request is 0, the request to get
3852 	 * the statistics are honoured as in this case
3853 	 * the firmware is just asked to clear the
3854 	 * statistics.
3855 	 */
3856 	if (stopReq == 1)
3857 		adapter->is_link_layer_stats_set = false;
3858 
3859 	hdd_exit();
3860 
3861 	return wlan_cfg80211_vendor_cmd_reply(skb);
3862 }
3863 
3864 /**
3865  * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
3866  * @wiphy: Pointer to wiphy
3867  * @wdev: Pointer to wdev
3868  * @data: Pointer to data
3869  * @data_len: Data length
3870  *
3871  * Return: 0 if success, non-zero for failure
3872  */
wlan_hdd_cfg80211_ll_stats_clear(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3873 int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
3874 					struct wireless_dev *wdev,
3875 					const void *data,
3876 					int data_len)
3877 {
3878 	int errno;
3879 	struct osif_vdev_sync *vdev_sync;
3880 
3881 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3882 	if (errno)
3883 		return errno;
3884 
3885 	errno = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
3886 
3887 	osif_vdev_sync_op_stop(vdev_sync);
3888 
3889 	return errno;
3890 }
3891 
3892 /**
3893  * wlan_hdd_clear_link_layer_stats() - clear link layer stats
3894  * @adapter: pointer to adapter
3895  *
3896  * Wrapper function to clear link layer stats.
3897  * return - void
3898  */
wlan_hdd_clear_link_layer_stats(struct hdd_adapter * adapter)3899 void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter)
3900 {
3901 	tSirLLStatsClearReq link_layer_stats_clear_req;
3902 	mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
3903 
3904 	link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC |
3905 		WIFI_STATS_IFACE_ALL_PEER | WIFI_STATS_IFACE_CONTENTION;
3906 	link_layer_stats_clear_req.stopReq = 0;
3907 	link_layer_stats_clear_req.reqId = 1;
3908 	link_layer_stats_clear_req.staId = adapter->deflink->vdev_id;
3909 	sme_ll_stats_clear_req(mac_handle, &link_layer_stats_clear_req);
3910 }
3911 
3912 /**
3913  * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
3914  * @wifi_peer_info: peer information
3915  * @vendor_event: buffer for vendor event
3916  *
3917  * Return: 0 success
3918  */
3919 static inline int
hdd_populate_per_peer_ps_info(struct wifi_peer_info * wifi_peer_info,struct sk_buff * vendor_event)3920 hdd_populate_per_peer_ps_info(struct wifi_peer_info *wifi_peer_info,
3921 			      struct sk_buff *vendor_event)
3922 {
3923 	if (!wifi_peer_info) {
3924 		hdd_err("Invalid pointer to peer info.");
3925 		return -EINVAL;
3926 	}
3927 
3928 	if (nla_put_u32(vendor_event,
3929 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
3930 			wifi_peer_info->power_saving) ||
3931 	    nla_put(vendor_event,
3932 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
3933 		    QDF_MAC_ADDR_SIZE, &wifi_peer_info->peer_macaddr)) {
3934 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
3935 		return -EINVAL;
3936 	}
3937 	return 0;
3938 }
3939 
3940 /**
3941  * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
3942  * @data: stats for peer STA
3943  * @vendor_event: buffer for vendor event
3944  *
3945  * Return: 0 success
3946  */
hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat * data,struct sk_buff * vendor_event)3947 static int hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat *data,
3948 					  struct sk_buff *vendor_event)
3949 {
3950 	uint32_t peer_num, i;
3951 	struct wifi_peer_info *wifi_peer_info;
3952 	struct nlattr *peer_info, *peers;
3953 
3954 	if (!data) {
3955 		hdd_err("Invalid pointer to Wifi peer stat.");
3956 		return -EINVAL;
3957 	}
3958 
3959 	peer_num = data->num_peers;
3960 	if (peer_num == 0) {
3961 		hdd_err("Peer number is zero.");
3962 		return -EINVAL;
3963 	}
3964 
3965 	if (nla_put_u32(vendor_event,
3966 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
3967 			peer_num)) {
3968 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
3969 		return -EINVAL;
3970 	}
3971 
3972 	peer_info = nla_nest_start(vendor_event,
3973 			       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
3974 	if (!peer_info) {
3975 		hdd_err("nla_nest_start failed");
3976 		return -EINVAL;
3977 	}
3978 
3979 	for (i = 0; i < peer_num; i++) {
3980 		wifi_peer_info = &data->peer_info[i];
3981 		peers = nla_nest_start(vendor_event, i);
3982 
3983 		if (!peers) {
3984 			hdd_err("nla_nest_start failed");
3985 			return -EINVAL;
3986 		}
3987 
3988 		if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
3989 			return -EINVAL;
3990 
3991 		nla_nest_end(vendor_event, peers);
3992 	}
3993 	nla_nest_end(vendor_event, peer_info);
3994 
3995 	return 0;
3996 }
3997 
3998 /**
3999  * hdd_populate_tx_failure_info() - populate TX failure info
4000  * @tx_fail: TX failure info
4001  * @skb: buffer for vendor event
4002  *
4003  * Return: 0 Success
4004  */
4005 static inline int
hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail * tx_fail,struct sk_buff * skb)4006 hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
4007 			     struct sk_buff *skb)
4008 {
4009 	int status = 0;
4010 
4011 	if (!tx_fail || !skb)
4012 		return -EINVAL;
4013 
4014 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
4015 			tx_fail->tid) ||
4016 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
4017 			tx_fail->msdu_num) ||
4018 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
4019 			tx_fail->status)) {
4020 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4021 		status = -EINVAL;
4022 	}
4023 
4024 	return status;
4025 }
4026 
4027 /**
4028  * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
4029  * @cca: cca info array for all channels
4030  * @vendor_event: vendor event buffer
4031  *
4032  * Return: 0 Success, EINVAL failure
4033  */
4034 static int
hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats * cca,struct sk_buff * vendor_event)4035 hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
4036 				   struct sk_buff *vendor_event)
4037 {
4038 	/* There might be no CCA info for a channel */
4039 	if (!cca)
4040 		return 0;
4041 
4042 	if (nla_put_u32(vendor_event,
4043 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
4044 			cca->idle_time) ||
4045 	    nla_put_u32(vendor_event,
4046 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
4047 			cca->tx_time) ||
4048 	    nla_put_u32(vendor_event,
4049 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
4050 			cca->rx_in_bss_time) ||
4051 	    nla_put_u32(vendor_event,
4052 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
4053 			cca->rx_out_bss_time) ||
4054 	    nla_put_u32(vendor_event,
4055 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
4056 			cca->rx_busy_time) ||
4057 	    nla_put_u32(vendor_event,
4058 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
4059 			cca->rx_in_bad_cond_time) ||
4060 	    nla_put_u32(vendor_event,
4061 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
4062 			cca->tx_in_bad_cond_time) ||
4063 	    nla_put_u32(vendor_event,
4064 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
4065 			cca->wlan_not_avail_time) ||
4066 	    nla_put_u32(vendor_event,
4067 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
4068 			cca->vdev_id)) {
4069 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4070 		return -EINVAL;
4071 	}
4072 	return 0;
4073 }
4074 
4075 /**
4076  * hdd_populate_wifi_signal_info - put chain signal info
4077  * @peer_signal: RF chain signal info
4078  * @skb: vendor event buffer
4079  *
4080  * Return: 0 Success, EINVAL failure
4081  */
4082 static int
hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats * peer_signal,struct sk_buff * skb)4083 hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
4084 			      struct sk_buff *skb)
4085 {
4086 	uint32_t i, chain_count;
4087 	struct nlattr *chains, *att;
4088 
4089 	/* There might be no signal info for a peer */
4090 	if (!peer_signal)
4091 		return 0;
4092 
4093 	chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
4094 		      peer_signal->num_chain : WIFI_MAX_CHAINS;
4095 	if (nla_put_u32(skb,
4096 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
4097 			chain_count)) {
4098 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4099 		return -EINVAL;
4100 	}
4101 
4102 	att = nla_nest_start(skb,
4103 			     QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
4104 	if (!att) {
4105 		hdd_err("nla_nest_start failed");
4106 		return -EINVAL;
4107 	}
4108 
4109 	for (i = 0; i < chain_count; i++) {
4110 		chains = nla_nest_start(skb, i);
4111 
4112 		if (!chains) {
4113 			hdd_err("nla_nest_start failed");
4114 			return -EINVAL;
4115 		}
4116 
4117 		hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
4118 			  peer_signal->per_ant_snr[i],
4119 			  peer_signal->nf[i],
4120 			  peer_signal->per_ant_rx_mpdus[i],
4121 			  peer_signal->per_ant_tx_mpdus[i]);
4122 		if (nla_put_u32(skb,
4123 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
4124 				peer_signal->per_ant_snr[i]) ||
4125 		    nla_put_u32(skb,
4126 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
4127 				peer_signal->nf[i]) ||
4128 		    nla_put_u32(skb,
4129 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
4130 				peer_signal->per_ant_rx_mpdus[i]) ||
4131 		    nla_put_u32(skb,
4132 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
4133 				peer_signal->per_ant_tx_mpdus[i])) {
4134 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4135 			return -EINVAL;
4136 		}
4137 		nla_nest_end(skb, chains);
4138 	}
4139 	nla_nest_end(skb, att);
4140 
4141 	return 0;
4142 }
4143 
4144 /**
4145  * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
4146  * @tx_stats: tx info
4147  * @skb: vendor event buffer
4148  *
4149  * Return: 0 Success, EINVAL failure
4150  */
4151 static int
hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx * tx_stats,struct sk_buff * skb)4152 hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
4153 				 struct sk_buff *skb)
4154 {
4155 	uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
4156 
4157 	/* There might be no TX info for a peer */
4158 	if (!tx_stats)
4159 		return 0;
4160 
4161 	agg_size = tx_stats->mpdu_aggr_size;
4162 	succ_mcs = tx_stats->success_mcs;
4163 	fail_mcs = tx_stats->fail_mcs;
4164 	delay = tx_stats->delay;
4165 
4166 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
4167 			tx_stats->msdus) ||
4168 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
4169 			tx_stats->mpdus) ||
4170 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
4171 			tx_stats->ppdus) ||
4172 	    nla_put_u32(skb,
4173 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
4174 			tx_stats->bytes) ||
4175 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
4176 			tx_stats->drops) ||
4177 	    nla_put_u32(skb,
4178 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
4179 			tx_stats->drop_bytes) ||
4180 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
4181 			tx_stats->retries) ||
4182 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
4183 			tx_stats->failed) ||
4184 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
4185 			tx_stats->aggr_len) ||
4186 	    nla_put_u32(skb,
4187 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
4188 			tx_stats->success_mcs_len) ||
4189 	    nla_put_u32(skb,
4190 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
4191 			tx_stats->fail_mcs_len) ||
4192 	    nla_put_u32(skb,
4193 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
4194 			tx_stats->delay_len))
4195 		goto put_attr_fail;
4196 
4197 	if (agg_size) {
4198 		if (nla_put(skb,
4199 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
4200 			    tx_stats->aggr_len, agg_size))
4201 			goto put_attr_fail;
4202 	}
4203 
4204 	if (succ_mcs) {
4205 		if (nla_put(skb,
4206 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
4207 			    tx_stats->success_mcs_len, succ_mcs))
4208 			goto put_attr_fail;
4209 	}
4210 
4211 	if (fail_mcs) {
4212 		if (nla_put(skb,
4213 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
4214 			    tx_stats->fail_mcs_len, fail_mcs))
4215 			goto put_attr_fail;
4216 	}
4217 
4218 	if (delay) {
4219 		if (nla_put(skb,
4220 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
4221 			    tx_stats->delay_len, delay))
4222 			goto put_attr_fail;
4223 	}
4224 	return 0;
4225 
4226 put_attr_fail:
4227 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4228 	return -EINVAL;
4229 }
4230 
4231 /**
4232  * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
4233  * @rx_stats: rx info
4234  * @skb: vendor event buffer
4235  *
4236  * Return: 0 Success, EINVAL failure
4237  */
4238 static int
hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx * rx_stats,struct sk_buff * skb)4239 hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
4240 				 struct sk_buff *skb)
4241 {
4242 	uint32_t *mcs, *aggr;
4243 
4244 	/* There might be no RX info for a peer */
4245 	if (!rx_stats)
4246 		return 0;
4247 
4248 	aggr = rx_stats->mpdu_aggr;
4249 	mcs = rx_stats->mcs;
4250 
4251 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
4252 			rx_stats->mpdus) ||
4253 	    nla_put_u32(skb,
4254 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
4255 			rx_stats->bytes) ||
4256 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
4257 			rx_stats->ppdus) ||
4258 	    nla_put_u32(skb,
4259 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
4260 			rx_stats->ppdu_bytes) ||
4261 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
4262 			rx_stats->mpdu_lost) ||
4263 	    nla_put_u32(skb,
4264 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
4265 			rx_stats->mpdu_retry) ||
4266 	    nla_put_u32(skb,
4267 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
4268 			rx_stats->mpdu_dup) ||
4269 	    nla_put_u32(skb,
4270 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
4271 			rx_stats->mpdu_discard) ||
4272 	    nla_put_u32(skb,
4273 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
4274 			rx_stats->aggr_len) ||
4275 	    nla_put_u32(skb,
4276 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
4277 			rx_stats->mcs_len))
4278 		goto put_attr_fail;
4279 
4280 	if (aggr) {
4281 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
4282 			    rx_stats->aggr_len, aggr))
4283 			goto put_attr_fail;
4284 	}
4285 
4286 	if (mcs) {
4287 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
4288 			    rx_stats->mcs_len, mcs))
4289 			goto put_attr_fail;
4290 	}
4291 
4292 	return 0;
4293 
4294 put_attr_fail:
4295 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4296 	return -EINVAL;
4297 }
4298 
4299 /**
4300  * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
4301  * @ac_stats: per AC stats
4302  * @skb: vendor event buffer
4303  *
4304  * Return: 0 Success, EINVAL failure
4305  */
4306 static int
hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats * ac_stats,struct sk_buff * skb)4307 hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
4308 			      struct sk_buff *skb)
4309 {
4310 	struct nlattr *wmm;
4311 
4312 	wmm = nla_nest_start(skb, ac_stats->type);
4313 	if (!wmm)
4314 		goto nest_start_fail;
4315 
4316 	if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
4317 	    hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
4318 		goto put_attr_fail;
4319 
4320 	nla_nest_end(skb, wmm);
4321 	return 0;
4322 
4323 nest_start_fail:
4324 	hdd_err("nla_nest_start failed");
4325 	return -EINVAL;
4326 
4327 put_attr_fail:
4328 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4329 	return -EINVAL;
4330 }
4331 
4332 /**
4333  * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
4334  * @peers: peer stats
4335  * @skb: vendor event buffer
4336  *
4337  * Return: 0 Success, EINVAL failure
4338  */
4339 static int
hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats * peers,struct sk_buff * skb)4340 hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
4341 				   struct sk_buff *skb)
4342 {
4343 	uint32_t i;
4344 	struct nlattr *wmm_ac;
4345 
4346 	if (nla_put_u32(skb,
4347 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
4348 			peers->peer_id) ||
4349 	    nla_put_u32(skb,
4350 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
4351 			peers->vdev_id) ||
4352 	    nla_put_u32(skb,
4353 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
4354 			peers->sta_ps_inds) ||
4355 	    nla_put_u32(skb,
4356 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
4357 			peers->sta_ps_durs) ||
4358 	    nla_put_u32(skb,
4359 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
4360 			peers->rx_probe_reqs) ||
4361 	    nla_put_u32(skb,
4362 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
4363 			peers->rx_oth_mgmts) ||
4364 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
4365 		    QDF_MAC_ADDR_SIZE, peers->mac_address) ||
4366 	    hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
4367 		hdd_err("put peer signal attr failed");
4368 		return -EINVAL;
4369 	}
4370 
4371 	wmm_ac = nla_nest_start(skb,
4372 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
4373 	if (!wmm_ac) {
4374 		hdd_err("nla_nest_start failed");
4375 		return -EINVAL;
4376 	}
4377 
4378 	for (i = 0; i < WLAN_MAX_AC; i++) {
4379 		if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
4380 			hdd_err("put WMM AC attr failed");
4381 			return -EINVAL;
4382 		}
4383 	}
4384 
4385 	nla_nest_end(skb, wmm_ac);
4386 	return 0;
4387 }
4388 
4389 /**
4390  * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
4391  * @stats: link layer stats
4392  * @skb: vendor event buffer
4393  *
4394  * Return: 0 Success, EINVAL failure
4395  */
4396 static int
hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats * stats,struct sk_buff * skb)4397 hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
4398 			       struct sk_buff *skb)
4399 {
4400 	uint32_t i;
4401 	struct nlattr *peer, *peer_info, *channels, *channel_info;
4402 
4403 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
4404 			stats->trigger_cond_id) ||
4405 	    nla_put_u32(skb,
4406 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
4407 			stats->cca_chgd_bitmap) ||
4408 	    nla_put_u32(skb,
4409 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
4410 			stats->sig_chgd_bitmap) ||
4411 	    nla_put_u32(skb,
4412 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
4413 			stats->tx_chgd_bitmap) ||
4414 	    nla_put_u32(skb,
4415 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
4416 			stats->rx_chgd_bitmap) ||
4417 	    nla_put_u32(skb,
4418 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
4419 			stats->channel_num) ||
4420 	    nla_put_u32(skb,
4421 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
4422 			stats->peer_num)) {
4423 		goto put_attr_fail;
4424 	}
4425 
4426 	channels = nla_nest_start(skb,
4427 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
4428 	if (!channels) {
4429 		hdd_err("nla_nest_start failed");
4430 		return -EINVAL;
4431 	}
4432 
4433 	for (i = 0; i < stats->channel_num; i++) {
4434 		channel_info = nla_nest_start(skb, i);
4435 		if (!channel_info) {
4436 			hdd_err("nla_nest_start failed");
4437 			return -EINVAL;
4438 		}
4439 
4440 		if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
4441 			goto put_attr_fail;
4442 		nla_nest_end(skb, channel_info);
4443 	}
4444 	nla_nest_end(skb, channels);
4445 
4446 	peer_info = nla_nest_start(skb,
4447 				   QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
4448 	if (!peer_info) {
4449 		hdd_err("nla_nest_start failed");
4450 		return -EINVAL;
4451 	}
4452 
4453 	for (i = 0; i < stats->peer_num; i++) {
4454 		peer = nla_nest_start(skb, i);
4455 		if (!peer) {
4456 			hdd_err("nla_nest_start failed");
4457 			return -EINVAL;
4458 		}
4459 
4460 		if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
4461 						       skb))
4462 			goto put_attr_fail;
4463 		nla_nest_end(skb, peer);
4464 	}
4465 
4466 	nla_nest_end(skb, peer_info);
4467 	return 0;
4468 
4469 put_attr_fail:
4470 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4471 	return -EINVAL;
4472 }
4473 
4474 /**
4475  * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
4476  * @ctx: HDD context
4477  * @rsp: msg from FW
4478  *
4479  * This function is an extension of
4480  * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
4481  * monitoring parameters offloaded to NL data and send the same to the
4482  * kernel/upper layers.
4483  *
4484  * Return: None
4485  */
wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,tSirLLStatsResults * rsp)4486 void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,
4487 						     tSirLLStatsResults *rsp)
4488 {
4489 	struct hdd_context *hdd_ctx;
4490 	struct sk_buff *skb;
4491 	uint32_t param_id, index;
4492 	struct wlan_hdd_link_info *link_info;
4493 	struct wifi_peer_stat *peer_stats;
4494 	uint8_t *results;
4495 	int status;
4496 
4497 	hdd_enter();
4498 
4499 	if (!rsp) {
4500 		hdd_err("Invalid result.");
4501 		return;
4502 	}
4503 
4504 	hdd_ctx = hdd_handle_to_context(ctx);
4505 	status = wlan_hdd_validate_context(hdd_ctx);
4506 	if (0 != status)
4507 		return;
4508 
4509 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->ifaceId);
4510 	if (!link_info) {
4511 		hdd_err("vdev_id %d does not exist with host.", rsp->ifaceId);
4512 		return;
4513 	}
4514 
4515 	index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
4516 	skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
4517 					       LL_STATS_EVENT_BUF_SIZE +
4518 					       NLMSG_HDRLEN,
4519 					       index, GFP_KERNEL);
4520 	if (!skb) {
4521 		hdd_err("wlan_cfg80211_vendor_event_alloc failed.");
4522 		return;
4523 	}
4524 
4525 	results = rsp->results;
4526 	param_id = rsp->paramId;
4527 	hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK",
4528 		 rsp->paramId, rsp->ifaceId, rsp->results);
4529 	if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
4530 		peer_stats = (struct wifi_peer_stat *)results;
4531 		status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
4532 	} else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
4533 		struct sir_wifi_iface_tx_fail *tx_fail;
4534 
4535 		tx_fail = (struct sir_wifi_iface_tx_fail *)results;
4536 		status = hdd_populate_tx_failure_info(tx_fail, skb);
4537 	} else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
4538 		hdd_info("MAC counters stats");
4539 		status = hdd_populate_wifi_ll_ext_stats(
4540 				(struct sir_wifi_ll_ext_stats *)
4541 				rsp->results, skb);
4542 	} else {
4543 		hdd_info("Unknown link layer stats");
4544 		status = -EINVAL;
4545 	}
4546 
4547 	if (status == 0)
4548 		wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
4549 	else
4550 		wlan_cfg80211_vendor_free_skb(skb);
4551 	hdd_exit();
4552 }
4553 
4554 const struct nla_policy
4555 qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
4556 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
4557 		.type = NLA_U32
4558 	},
4559 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
4560 		.type = NLA_U32
4561 	},
4562 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG] = {
4563 		.type = NLA_U32
4564 	},
4565 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID] = {
4566 		.type = NLA_U32
4567 	},
4568 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU] = {
4569 		.type = NLA_U32
4570 	},
4571 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS] = {
4572 		.type = NLA_U32
4573 	},
4574 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE] = {
4575 		.type = NLA_U32
4576 	},
4577 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS] = {
4578 		.type = NLA_U32
4579 	},
4580 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
4581 		.type = NLA_U32
4582 	},
4583 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE] = {
4584 		.type = NLA_U32
4585 	},
4586 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID] = {
4587 		.type = NLA_U32
4588 	},
4589 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID] = {
4590 		.type = NLA_U32
4591 	},
4592 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
4593 		.type = NLA_U32
4594 	},
4595 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
4596 		.type = NLA_U32
4597 	},
4598 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
4599 		.type = NLA_U32
4600 	},
4601 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
4602 		.type = NLA_U32
4603 	},
4604 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM] = {
4605 		.type = NLA_U32
4606 	},
4607 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM] = {
4608 		.type = NLA_U32
4609 	},
4610 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS] = {
4611 		.type = NLA_U32
4612 	},
4613 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER] = {
4614 		.type = NLA_U32
4615 	},
4616 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
4617 		.type = NLA_U32
4618 	},
4619 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
4620 		.type = NLA_U32
4621 	},
4622 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
4623 		.type = NLA_U32
4624 	},
4625 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
4626 		.type = NLA_U32
4627 	},
4628 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
4629 		.type = NLA_U32
4630 	},
4631 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
4632 		.type = NLA_U32
4633 	},
4634 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
4635 		.type = NLA_U32
4636 	},
4637 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
4638 		.type = NLA_U32
4639 	},
4640 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
4641 		.type = NLA_U32
4642 	},
4643 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM] = {
4644 		.type = NLA_U32
4645 	},
4646 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM] = {
4647 		.type = NLA_U32
4648 	},
4649 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM] = {
4650 		.type = NLA_U32
4651 	},
4652 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
4653 		.type = NLA_U32
4654 	},
4655 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
4656 		.type = NLA_U32
4657 	},
4658 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
4659 		.type = NLA_U32
4660 	},
4661 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE] = {
4662 		.type = NLA_U32
4663 	},
4664 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
4665 		.type = NLA_U32
4666 	},
4667 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
4668 		.type = NLA_U32
4669 	},
4670 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
4671 		.type = NLA_U32
4672 	},
4673 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
4674 		.type = NLA_U32
4675 	},
4676 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
4677 		.type = NLA_U32
4678 	},
4679 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
4680 		.type = NLA_U32
4681 	},
4682 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
4683 		.type = NLA_U32
4684 	},
4685 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
4686 		.type = NLA_U32
4687 	},
4688 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
4689 		.type = NLA_U32
4690 	},
4691 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM] = {
4692 		.type = NLA_U32
4693 	},
4694 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM] = {
4695 		.type = NLA_U32
4696 	},
4697 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
4698 		.type = NLA_U32
4699 	},
4700 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
4701 		.type = NLA_U32
4702 	},
4703 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
4704 		.type = NLA_U32
4705 	},
4706 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
4707 		.type = NLA_U32
4708 	},
4709 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
4710 		.type = NLA_U32
4711 	},
4712 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
4713 		.type = NLA_U32
4714 	},
4715 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
4716 		.type = NLA_U32
4717 	},
4718 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
4719 		.type = NLA_U32
4720 	},
4721 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME] = {
4722 		.type = NLA_U32
4723 	},
4724 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
4725 		.type = NLA_U32
4726 	},
4727 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
4728 		.type = NLA_U32
4729 	},
4730 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
4731 		.type = NLA_U32
4732 	},
4733 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
4734 		.type = NLA_U32
4735 	},
4736 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
4737 		.type = NLA_U32
4738 	},
4739 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
4740 		.type = NLA_U32
4741 	},
4742 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM] = {
4743 		.type = NLA_U32
4744 	},
4745 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL] = {
4746 		.type = NLA_U32
4747 	},
4748 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
4749 		.type = NLA_U32
4750 	},
4751 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
4752 		.type = NLA_U32
4753 	},
4754 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON] = {
4755 		.type = NLA_U32
4756 	},
4757 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON] = {
4758 		.type = NLA_U32
4759 	},
4760 };
4761 
4762 /**
4763  * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
4764  * @wiphy: wiphy handle
4765  * @wdev: wdev handle
4766  * @data: user layer input
4767  * @data_len: length of user layer input
4768  *
4769  * this function is called in ssr protected environment.
4770  *
4771  * return: 0 success, none zero for failure
4772  */
__wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)4773 static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
4774 						      struct wireless_dev *wdev,
4775 						      const void *data,
4776 						      int data_len)
4777 {
4778 	QDF_STATUS status;
4779 	int errno;
4780 	uint32_t period;
4781 	struct net_device *dev = wdev->netdev;
4782 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4783 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
4784 	struct sir_ll_ext_stats_threshold thresh = {0,};
4785 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
4786 
4787 	hdd_enter_dev(dev);
4788 
4789 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
4790 		hdd_warn("command not allowed in ftm mode");
4791 		return -EPERM;
4792 	}
4793 
4794 	errno = wlan_hdd_validate_context(hdd_ctx);
4795 	if (errno)
4796 		return -EPERM;
4797 
4798 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
4799 				    (struct nlattr *)data, data_len,
4800 				    qca_wlan_vendor_ll_ext_policy)) {
4801 		hdd_err("maximum attribute not present");
4802 		return -EPERM;
4803 	}
4804 
4805 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
4806 		period = nla_get_u32(tb[
4807 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
4808 
4809 		if (period != 0 && period < LL_STATS_MIN_PERIOD)
4810 			period = LL_STATS_MIN_PERIOD;
4811 
4812 		/*
4813 		 * Only enable/disable counters.
4814 		 * Keep the last threshold settings.
4815 		 */
4816 		goto set_period;
4817 	}
4818 
4819 	/* global thresh is not enabled */
4820 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
4821 		thresh.global = false;
4822 		hdd_warn("global thresh is not set");
4823 	} else {
4824 		thresh.global_threshold = nla_get_u32(tb[
4825 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
4826 		thresh.global = true;
4827 		hdd_debug("globle thresh is %d", thresh.global_threshold);
4828 	}
4829 
4830 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
4831 		thresh.global = false;
4832 		hdd_warn("global thresh is not enabled");
4833 	} else {
4834 		thresh.global = nla_get_u32(tb[
4835 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
4836 		hdd_debug("global is %d", thresh.global);
4837 	}
4838 
4839 	thresh.enable_bitmap = false;
4840 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
4841 		thresh.tx_bitmap = nla_get_u32(tb[
4842 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
4843 		thresh.enable_bitmap = true;
4844 	}
4845 
4846 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
4847 		thresh.rx_bitmap = nla_get_u32(tb[
4848 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
4849 		thresh.enable_bitmap = true;
4850 	}
4851 
4852 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
4853 		thresh.cca_bitmap = nla_get_u32(tb[
4854 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
4855 		thresh.enable_bitmap = true;
4856 	}
4857 
4858 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
4859 		thresh.signal_bitmap = nla_get_u32(tb[
4860 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
4861 		thresh.enable_bitmap = true;
4862 	}
4863 
4864 	if (!thresh.global && !thresh.enable_bitmap) {
4865 		hdd_warn("threshold will be disabled.");
4866 		thresh.enable = false;
4867 
4868 		/* Just disable threshold */
4869 		goto set_thresh;
4870 	} else {
4871 		thresh.enable = true;
4872 	}
4873 
4874 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
4875 		thresh.tx.msdu = nla_get_u32(tb[
4876 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
4877 	}
4878 
4879 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
4880 		thresh.tx.mpdu = nla_get_u32(tb[
4881 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
4882 	}
4883 
4884 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
4885 		thresh.tx.ppdu = nla_get_u32(tb[
4886 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
4887 	}
4888 
4889 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
4890 		thresh.tx.bytes = nla_get_u32(tb[
4891 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
4892 	}
4893 
4894 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
4895 		thresh.tx.msdu_drop = nla_get_u32(
4896 			tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
4897 	}
4898 
4899 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
4900 		thresh.tx.byte_drop = nla_get_u32(tb[
4901 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
4902 	}
4903 
4904 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
4905 		thresh.tx.mpdu_retry = nla_get_u32(tb[
4906 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
4907 	}
4908 
4909 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
4910 		thresh.tx.mpdu_fail = nla_get_u32(tb[
4911 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
4912 	}
4913 
4914 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
4915 		thresh.tx.ppdu_fail = nla_get_u32(tb[
4916 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
4917 	}
4918 
4919 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
4920 		thresh.tx.aggregation = nla_get_u32(tb[
4921 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
4922 	}
4923 
4924 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
4925 		thresh.tx.succ_mcs = nla_get_u32(tb[
4926 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
4927 	}
4928 
4929 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
4930 		thresh.tx.fail_mcs = nla_get_u32(tb[
4931 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
4932 	}
4933 
4934 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
4935 		thresh.tx.delay = nla_get_u32(tb[
4936 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
4937 	}
4938 
4939 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
4940 		thresh.rx.mpdu = nla_get_u32(tb[
4941 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
4942 	}
4943 
4944 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
4945 		thresh.rx.bytes = nla_get_u32(tb[
4946 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
4947 	}
4948 
4949 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
4950 		thresh.rx.ppdu = nla_get_u32(tb[
4951 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
4952 	}
4953 
4954 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
4955 		thresh.rx.ppdu_bytes = nla_get_u32(tb[
4956 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
4957 	}
4958 
4959 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
4960 		thresh.rx.mpdu_lost = nla_get_u32(tb[
4961 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
4962 	}
4963 
4964 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
4965 		thresh.rx.mpdu_retry = nla_get_u32(tb[
4966 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
4967 	}
4968 
4969 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
4970 		thresh.rx.mpdu_dup = nla_get_u32(tb[
4971 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
4972 	}
4973 
4974 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
4975 		thresh.rx.mpdu_discard = nla_get_u32(tb[
4976 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
4977 	}
4978 
4979 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
4980 		thresh.rx.aggregation = nla_get_u32(tb[
4981 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
4982 	}
4983 
4984 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
4985 		thresh.rx.mcs = nla_get_u32(tb[
4986 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
4987 	}
4988 
4989 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
4990 		thresh.rx.ps_inds = nla_get_u32(tb[
4991 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
4992 	}
4993 
4994 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
4995 		thresh.rx.ps_durs = nla_get_u32(tb[
4996 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
4997 	}
4998 
4999 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
5000 		thresh.rx.probe_reqs = nla_get_u32(tb[
5001 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
5002 	}
5003 
5004 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
5005 		thresh.rx.other_mgmt = nla_get_u32(tb[
5006 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
5007 	}
5008 
5009 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
5010 		thresh.cca.idle_time = nla_get_u32(tb[
5011 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
5012 	}
5013 
5014 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
5015 		thresh.cca.tx_time = nla_get_u32(tb[
5016 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
5017 	}
5018 
5019 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
5020 		thresh.cca.rx_in_bss_time = nla_get_u32(tb[
5021 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
5022 	}
5023 
5024 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
5025 		thresh.cca.rx_out_bss_time = nla_get_u32(tb[
5026 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
5027 	}
5028 
5029 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
5030 		thresh.cca.rx_busy_time = nla_get_u32(tb[
5031 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
5032 	}
5033 
5034 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
5035 		thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
5036 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
5037 	}
5038 
5039 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
5040 		thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
5041 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
5042 	}
5043 
5044 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
5045 		thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
5046 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
5047 	}
5048 
5049 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
5050 		thresh.signal.snr = nla_get_u32(tb[
5051 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
5052 	}
5053 
5054 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
5055 		thresh.signal.nf = nla_get_u32(tb[
5056 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
5057 	}
5058 
5059 set_thresh:
5060 	hdd_info("send thresh settings to target");
5061 	status = sme_ll_stats_set_thresh(hdd_ctx->mac_handle, &thresh);
5062 	if (QDF_IS_STATUS_ERROR(status)) {
5063 		hdd_err("sme_ll_stats_set_thresh failed.");
5064 		return -EINVAL;
5065 	}
5066 	return 0;
5067 
5068 set_period:
5069 	hdd_info("send period to target");
5070 	errno = wma_cli_set_command(adapter->deflink->vdev_id,
5071 				    wmi_pdev_param_stats_observation_period,
5072 				    period, PDEV_CMD);
5073 	if (errno) {
5074 		hdd_err("wma_cli_set_command set_period failed.");
5075 		return -EINVAL;
5076 	}
5077 	return 0;
5078 }
5079 
5080 /**
5081  * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
5082  * @wiphy: wiphy handle
5083  * @wdev: wdev handle
5084  * @data: user layer input
5085  * @data_len: length of user layer input
5086  *
5087  * return: 0 success, einval failure
5088  */
wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5089 int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
5090 					     struct wireless_dev *wdev,
5091 					     const void *data,
5092 					     int data_len)
5093 {
5094 	int errno;
5095 	struct osif_vdev_sync *vdev_sync;
5096 
5097 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5098 	if (errno)
5099 		return errno;
5100 
5101 	errno = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
5102 							   data, data_len);
5103 
5104 	osif_vdev_sync_op_stop(vdev_sync);
5105 
5106 	return errno;
5107 }
5108 
5109 #else
wlan_hdd_stats_request_needed(struct hdd_adapter * adapter)5110 static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
5111 {
5112 	return QDF_STATUS_SUCCESS;
5113 }
5114 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
5115 
5116 /**
5117  * __wlan_hdd_cfg80211_connected_chan_stats_request() - stats request for
5118  * currently connected channel
5119  * @wiphy: Pointer to wiphy
5120  * @wdev: Pointer to wdev
5121  * @data: Pointer to data
5122  * @data_len: Data length
5123  *
5124  * Return: int
5125  */
5126 static int
__wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5127 __wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy *wiphy,
5128 						 struct wireless_dev *wdev,
5129 						 const void *data,
5130 						 int data_len)
5131 {
5132 	struct net_device *dev = wdev->netdev;
5133 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5134 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
5135 	bool is_vdev_connected;
5136 	enum QDF_OPMODE mode;
5137 	QDF_STATUS status;
5138 
5139 	is_vdev_connected = hdd_cm_is_vdev_connected(adapter->deflink);
5140 	mode = adapter->device_mode;
5141 
5142 	if (mode != QDF_STA_MODE || !is_vdev_connected) {
5143 		hdd_debug("vdev %d: reject chan stats req, mode:%d, conn:%d",
5144 			  adapter->deflink->vdev_id, mode, is_vdev_connected);
5145 		return -EPERM;
5146 	}
5147 
5148 	status = ucfg_mlme_connected_chan_stats_request(hdd_ctx->psoc,
5149 					adapter->deflink->vdev_id);
5150 	return qdf_status_to_os_return(status);
5151 }
5152 
wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5153 int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy,
5154 					       struct wireless_dev *wdev,
5155 					       const void *data,
5156 					       int data_len)
5157 {
5158 	int errno;
5159 	struct osif_vdev_sync *vdev_sync;
5160 
5161 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5162 	if (errno)
5163 		return errno;
5164 
5165 	errno = __wlan_hdd_cfg80211_connected_chan_stats_request(wiphy, wdev,
5166 								 data,
5167 								 data_len);
5168 
5169 	osif_vdev_sync_op_stop(vdev_sync);
5170 
5171 	return errno;
5172 }
5173 
5174 #ifdef WLAN_FEATURE_STATS_EXT
5175 /**
5176  * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
5177  * @wiphy: Pointer to wiphy
5178  * @wdev: Pointer to wdev
5179  * @data: Pointer to data
5180  * @data_len: Data length
5181  *
5182  * Return: int
5183  */
__wlan_hdd_cfg80211_stats_ext_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5184 static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
5185 						 struct wireless_dev *wdev,
5186 						 const void *data,
5187 						 int data_len)
5188 {
5189 	tStatsExtRequestReq stats_ext_req;
5190 	struct net_device *dev = wdev->netdev;
5191 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5192 	int ret_val;
5193 	QDF_STATUS status;
5194 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
5195 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
5196 	struct cdp_txrx_stats_req txrx_req = {0};
5197 
5198 	hdd_enter_dev(dev);
5199 
5200 	ret_val = wlan_hdd_validate_context(hdd_ctx);
5201 	if (ret_val)
5202 		return ret_val;
5203 
5204 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
5205 		hdd_err("Command not allowed in FTM mode");
5206 		return -EPERM;
5207 	}
5208 
5209 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
5210 		return -EINVAL;
5211 	/**
5212 	 * HTT_DBG_EXT_STATS_PDEV_RX
5213 	 */
5214 	txrx_req.stats = 2;
5215 	/* default value of secondary parameter is 0(mac_id) */
5216 	txrx_req.mac_id = 0;
5217 	status = cdp_txrx_stats_request(soc, adapter->deflink->vdev_id,
5218 					&txrx_req);
5219 	if (QDF_STATUS_SUCCESS != status) {
5220 		hdd_err_rl("Failed to get hw stats: %u", status);
5221 		ret_val = -EINVAL;
5222 	}
5223 
5224 	stats_ext_req.request_data_len = data_len;
5225 	stats_ext_req.request_data = (void *)data;
5226 
5227 	status = cdp_request_rx_hw_stats(soc, adapter->deflink->vdev_id);
5228 
5229 	if (QDF_STATUS_SUCCESS != status) {
5230 		hdd_err_rl("Failed to get hw stats: %u", status);
5231 		ret_val = -EINVAL;
5232 	}
5233 
5234 	status = sme_stats_ext_request(adapter->deflink->vdev_id,
5235 				       &stats_ext_req);
5236 
5237 	if (QDF_STATUS_SUCCESS != status) {
5238 		hdd_err_rl("Failed to get fw stats: %u", status);
5239 		ret_val = -EINVAL;
5240 	}
5241 
5242 	return ret_val;
5243 }
5244 
5245 /**
5246  * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
5247  * @wiphy: Pointer to wiphy
5248  * @wdev: Pointer to wdev
5249  * @data: Pointer to data
5250  * @data_len: Data length
5251  *
5252  * Return: int
5253  */
wlan_hdd_cfg80211_stats_ext_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5254 int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
5255 					struct wireless_dev *wdev,
5256 					const void *data,
5257 					int data_len)
5258 {
5259 	int errno;
5260 	struct osif_vdev_sync *vdev_sync;
5261 
5262 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5263 	if (errno)
5264 		return errno;
5265 
5266 	errno = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
5267 						      data, data_len);
5268 
5269 	osif_vdev_sync_op_stop(vdev_sync);
5270 
5271 	return errno;
5272 }
5273 
wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,struct stats_ext_event * data)5274 void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
5275 					  struct stats_ext_event *data)
5276 {
5277 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
5278 	struct sk_buff *vendor_event;
5279 	int status;
5280 	int ret_val;
5281 	struct wlan_hdd_link_info *link_info;
5282 	enum qca_nl80211_vendor_subcmds_index index =
5283 		QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX;
5284 
5285 	status = wlan_hdd_validate_context(hdd_ctx);
5286 	if (status)
5287 		return;
5288 
5289 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, data->vdev_id);
5290 	if (!link_info) {
5291 		hdd_err("vdev_id %d does not exist with host", data->vdev_id);
5292 		return;
5293 	}
5294 
5295 	vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
5296 							data->event_data_len +
5297 							sizeof(uint32_t) +
5298 							NLMSG_HDRLEN +
5299 							NLMSG_HDRLEN,
5300 							index, GFP_KERNEL);
5301 	if (!vendor_event) {
5302 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
5303 		return;
5304 	}
5305 
5306 	ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
5307 			      link_info->adapter->dev->ifindex);
5308 	if (ret_val) {
5309 		hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
5310 		wlan_cfg80211_vendor_free_skb(vendor_event);
5311 
5312 		return;
5313 	}
5314 
5315 	ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
5316 			  data->event_data_len, data->event_data);
5317 
5318 	if (ret_val) {
5319 		hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
5320 		wlan_cfg80211_vendor_free_skb(vendor_event);
5321 
5322 		return;
5323 	}
5324 
5325 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5326 
5327 }
5328 
5329 void
wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,struct sir_sme_rx_aggr_hole_ind * pmsg)5330 wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
5331 				      struct sir_sme_rx_aggr_hole_ind *pmsg)
5332 {
5333 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
5334 	int status;
5335 	uint32_t data_size, hole_info_size;
5336 	struct sk_buff *vendor_event;
5337 	enum qca_nl80211_vendor_subcmds_index index =
5338 		QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX;
5339 
5340 	status = wlan_hdd_validate_context(hdd_ctx);
5341 	if (0 != status)
5342 		return;
5343 
5344 	if (!pmsg) {
5345 		hdd_err("msg received here is null");
5346 		return;
5347 	}
5348 
5349 	hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
5350 	data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
5351 
5352 	vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
5353 							data_size +
5354 							NLMSG_HDRLEN +
5355 							NLMSG_HDRLEN,
5356 							index, GFP_KERNEL);
5357 	if (!vendor_event) {
5358 		hdd_err("vendor_event_alloc failed for STATS_EXT2");
5359 		return;
5360 	}
5361 
5362 	if (nla_put_u32(vendor_event,
5363 			QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
5364 			pmsg->hole_cnt)) {
5365 		hdd_err("%s put fail",
5366 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
5367 		wlan_cfg80211_vendor_free_skb(vendor_event);
5368 		return;
5369 	}
5370 	if (nla_put(vendor_event,
5371 		    QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
5372 		    hole_info_size,
5373 		    (void *)(pmsg->hole_info_array))) {
5374 		hdd_err("%s put fail",
5375 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
5376 		wlan_cfg80211_vendor_free_skb(vendor_event);
5377 		return;
5378 	}
5379 
5380 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5381 }
5382 
5383 #else
wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,struct stats_ext_event * data)5384 void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
5385 					  struct stats_ext_event *data)
5386 {
5387 }
5388 
5389 void
wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,struct sir_sme_rx_aggr_hole_ind * pmsg)5390 wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
5391 				      struct sir_sme_rx_aggr_hole_ind *pmsg)
5392 {
5393 }
5394 #endif /* End of WLAN_FEATURE_STATS_EXT */
5395 
5396 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
5397 /**
5398  * enum roam_event_rt_info_reset - Reset the notif param value of struct
5399  * roam_event_rt_info to 0
5400  * @ROAM_EVENT_RT_INFO_RESET: Reset the value to 0
5401  */
5402 enum roam_event_rt_info_reset {
5403 	ROAM_EVENT_RT_INFO_RESET = 0,
5404 };
5405 
5406 /**
5407  * struct roam_ap - Roamed/Failed AP info
5408  * @num_cand: number of candidate APs
5409  * @bssid:    BSSID of roamed/failed AP
5410  * @rssi:     RSSI of roamed/failed AP
5411  * @freq:     Frequency of roamed/failed AP
5412  */
5413 struct roam_ap {
5414 	uint32_t num_cand;
5415 	struct qdf_mac_addr bssid;
5416 	int8_t rssi;
5417 	uint16_t freq;
5418 };
5419 
5420 /**
5421  * hdd_get_roam_rt_stats_event_len() - calculate length of skb required for
5422  * sending roam events stats.
5423  * @roam_stats: pointer to roam_stats_event structure
5424  * @idx:          TLV index of roam stats event
5425  *
5426  * Return: length of skb
5427  */
5428 static uint32_t
hdd_get_roam_rt_stats_event_len(struct roam_stats_event * roam_stats,uint8_t idx)5429 hdd_get_roam_rt_stats_event_len(struct roam_stats_event *roam_stats,
5430 				uint8_t idx)
5431 {
5432 	uint32_t len = 0;
5433 	uint8_t i = 0, num_cand = 0;
5434 
5435 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON  */
5436 	if (roam_stats->trigger[idx].present)
5437 		len += nla_total_size(sizeof(uint32_t));
5438 
5439 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON */
5440 	if (roam_stats->roam_event_param.roam_invoke_fail_reason)
5441 		len += nla_total_size(sizeof(uint32_t));
5442 
5443 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE */
5444 	if (roam_stats->roam_event_param.roam_scan_state)
5445 		len += nla_total_size(sizeof(uint8_t));
5446 
5447 	if (roam_stats->scan[idx].present) {
5448 		if (roam_stats->scan[idx].num_chan &&
5449 		    roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL)
5450 			for (i = 0; i < roam_stats->scan[idx].num_chan;)
5451 				i++;
5452 
5453 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST */
5454 		len += (nla_total_size(sizeof(uint32_t)) * i);
5455 
5456 		if (roam_stats->result[idx].present &&
5457 		    roam_stats->result[idx].fail_reason) {
5458 			num_cand++;
5459 		} else if (roam_stats->trigger[idx].present) {
5460 			for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5461 				if (roam_stats->scan[idx].ap[i].type == 2)
5462 					num_cand++;
5463 			}
5464 		}
5465 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO */
5466 		len += NLA_HDRLEN;
5467 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID */
5468 		len += (nla_total_size(QDF_MAC_ADDR_SIZE) * num_cand);
5469 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI */
5470 		len += (nla_total_size(sizeof(int32_t)) * num_cand);
5471 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ */
5472 		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
5473 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON */
5474 		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
5475 	}
5476 
5477 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE */
5478 	if (len)
5479 		len += nla_total_size(sizeof(uint32_t));
5480 
5481 	return len;
5482 }
5483 
5484 #define SUBCMD_ROAM_EVENTS_INDEX \
5485 	QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS_INDEX
5486 #define ROAM_SCAN_FREQ_LIST \
5487 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST
5488 #define ROAM_INVOKE_FAIL_REASON \
5489 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON
5490 #define ROAM_SCAN_STATE         QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE
5491 #define ROAM_EVENTS_CANDIDATE   QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO
5492 #define CANDIDATE_BSSID \
5493 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID
5494 #define CANDIDATE_RSSI \
5495 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI
5496 #define CANDIDATE_FREQ \
5497 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ
5498 #define ROAM_FAIL_REASON \
5499 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON
5500 
5501 /**
5502  * roam_rt_stats_fill_scan_freq() - Fill the scan frequency list from the
5503  * roam stats event.
5504  * @vendor_event: pointer to sk_buff structure
5505  * @idx:          TLV index of roam stats event
5506  * @roam_stats:   pointer to roam_stats_event structure
5507  *
5508  * Return: none
5509  */
5510 static void
roam_rt_stats_fill_scan_freq(struct sk_buff * vendor_event,uint8_t idx,struct roam_stats_event * roam_stats)5511 roam_rt_stats_fill_scan_freq(struct sk_buff *vendor_event, uint8_t idx,
5512 			     struct roam_stats_event *roam_stats)
5513 {
5514 	struct nlattr *nl_attr;
5515 	uint8_t i;
5516 
5517 	nl_attr = nla_nest_start(vendor_event, ROAM_SCAN_FREQ_LIST);
5518 	if (!nl_attr) {
5519 		hdd_err("nla nest start fail");
5520 		kfree_skb(vendor_event);
5521 		return;
5522 	}
5523 	if (roam_stats->scan[idx].num_chan &&
5524 	    roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL) {
5525 		for (i = 0; i < roam_stats->scan[idx].num_chan; i++) {
5526 			if (nla_put_u32(vendor_event, i,
5527 					roam_stats->scan[idx].chan_freq[i])) {
5528 				hdd_err("failed to put freq at index %d", i);
5529 				kfree_skb(vendor_event);
5530 				return;
5531 			}
5532 		}
5533 	}
5534 	nla_nest_end(vendor_event, nl_attr);
5535 }
5536 
5537 /**
5538  * roam_rt_stats_fill_cand_info() - Fill the roamed/failed AP info from the
5539  * roam stats event.
5540  * @vendor_event: pointer to sk_buff structure
5541  * @idx:          TLV index of roam stats event
5542  * @roam_stats:   pointer to roam_stats_event structure
5543  *
5544  * Return: none
5545  */
5546 static void
roam_rt_stats_fill_cand_info(struct sk_buff * vendor_event,uint8_t idx,struct roam_stats_event * roam_stats)5547 roam_rt_stats_fill_cand_info(struct sk_buff *vendor_event, uint8_t idx,
5548 			     struct roam_stats_event *roam_stats)
5549 {
5550 	struct nlattr *nl_attr, *nl_array;
5551 	struct roam_ap cand_ap = {0};
5552 	uint8_t i, num_cand = 0;
5553 
5554 	if (roam_stats->result[idx].present &&
5555 	    roam_stats->result[idx].fail_reason &&
5556 	    roam_stats->result[idx].fail_reason != ROAM_FAIL_REASON_UNKNOWN) {
5557 		num_cand++;
5558 		for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5559 			if (roam_stats->scan[idx].ap[i].type == 0 &&
5560 			    qdf_is_macaddr_equal(&roam_stats->
5561 						 result[idx].fail_bssid,
5562 						 &roam_stats->
5563 						 scan[idx].ap[i].bssid)) {
5564 				qdf_copy_macaddr(&cand_ap.bssid,
5565 						 &roam_stats->
5566 						 scan[idx].ap[i].bssid);
5567 				cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi;
5568 				cand_ap.freq = roam_stats->scan[idx].ap[i].freq;
5569 			}
5570 		}
5571 	} else if (roam_stats->trigger[idx].present) {
5572 		for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5573 			if (roam_stats->scan[idx].ap[i].type == 2) {
5574 				num_cand++;
5575 				qdf_copy_macaddr(&cand_ap.bssid,
5576 						 &roam_stats->
5577 						 scan[idx].ap[i].bssid);
5578 				cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi;
5579 				cand_ap.freq = roam_stats->scan[idx].ap[i].freq;
5580 			}
5581 		}
5582 	}
5583 
5584 	nl_array = nla_nest_start(vendor_event, ROAM_EVENTS_CANDIDATE);
5585 	if (!nl_array) {
5586 		hdd_err("nl array nest start fail");
5587 		kfree_skb(vendor_event);
5588 		return;
5589 	}
5590 	for (i = 0; i < num_cand; i++) {
5591 		nl_attr = nla_nest_start(vendor_event, i);
5592 		if (!nl_attr) {
5593 			hdd_err("nl attr nest start fail");
5594 			kfree_skb(vendor_event);
5595 			return;
5596 		}
5597 		if (nla_put(vendor_event, CANDIDATE_BSSID,
5598 			    sizeof(cand_ap.bssid), cand_ap.bssid.bytes)) {
5599 			hdd_err("%s put fail",
5600 				"ROAM_EVENTS_CANDIDATE_INFO_BSSID");
5601 			kfree_skb(vendor_event);
5602 			return;
5603 		}
5604 		if (nla_put_s32(vendor_event, CANDIDATE_RSSI, cand_ap.rssi)) {
5605 			hdd_err("%s put fail",
5606 				"ROAM_EVENTS_CANDIDATE_INFO_RSSI");
5607 			kfree_skb(vendor_event);
5608 			return;
5609 		}
5610 		if (nla_put_u32(vendor_event, CANDIDATE_FREQ, cand_ap.freq)) {
5611 			hdd_err("%s put fail",
5612 				"ROAM_EVENTS_CANDIDATE_INFO_FREQ");
5613 			kfree_skb(vendor_event);
5614 			return;
5615 		}
5616 		if (roam_stats->result[idx].present &&
5617 		    roam_stats->result[idx].fail_reason) {
5618 			if (nla_put_u32(vendor_event, ROAM_FAIL_REASON,
5619 					roam_stats->result[idx].fail_reason)) {
5620 				hdd_err("%s put fail",
5621 					"ROAM_EVENTS_CANDIDATE_FAIL_REASON");
5622 				kfree_skb(vendor_event);
5623 				return;
5624 			}
5625 		}
5626 		nla_nest_end(vendor_event, nl_attr);
5627 	}
5628 	nla_nest_end(vendor_event, nl_array);
5629 }
5630 
5631 static void
wlan_hdd_cfg80211_typical_roam_events_callback(struct wlan_hdd_link_info * link_info,struct roam_stats_event * roam_stats,uint8_t idx)5632 wlan_hdd_cfg80211_typical_roam_events_callback(struct wlan_hdd_link_info *link_info,
5633 					       struct roam_stats_event *roam_stats,
5634 					       uint8_t idx)
5635 {
5636 	uint32_t data_size, roam_event_type = 0;
5637 	struct sk_buff *vendor_event;
5638 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
5639 
5640 	if (wlan_hdd_validate_context(hdd_ctx)) {
5641 		hdd_err("Invalid hdd_ctx");
5642 		return;
5643 	}
5644 
5645 	data_size = hdd_get_roam_rt_stats_event_len(roam_stats, idx);
5646 	if (!data_size) {
5647 		hdd_err("No data requested");
5648 		return;
5649 	}
5650 
5651 	data_size += NLMSG_HDRLEN;
5652 	vendor_event =
5653 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
5654 						 &link_info->adapter->wdev,
5655 						 data_size,
5656 						 SUBCMD_ROAM_EVENTS_INDEX,
5657 						 GFP_KERNEL);
5658 
5659 	if (!vendor_event) {
5660 		hdd_err("vendor_event_alloc failed for ROAM_EVENTS_STATS");
5661 		return;
5662 	}
5663 
5664 	if (roam_stats->scan[idx].present && roam_stats->trigger[idx].present) {
5665 		roam_rt_stats_fill_scan_freq(vendor_event, idx, roam_stats);
5666 		roam_rt_stats_fill_cand_info(vendor_event, idx, roam_stats);
5667 	}
5668 
5669 	if (roam_stats->roam_event_param.roam_scan_state) {
5670 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_ROAM_SCAN_STATE;
5671 		if (nla_put_u8(vendor_event, ROAM_SCAN_STATE,
5672 			       roam_stats->roam_event_param.roam_scan_state)) {
5673 			hdd_err("%s put fail",
5674 				"VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE");
5675 			wlan_cfg80211_vendor_free_skb(vendor_event);
5676 			return;
5677 		}
5678 		roam_stats->roam_event_param.roam_scan_state =
5679 						ROAM_EVENT_RT_INFO_RESET;
5680 	}
5681 	if (roam_stats->trigger[idx].present) {
5682 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON;
5683 		if (nla_put_u32(vendor_event,
5684 				QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON,
5685 				roam_stats->trigger[idx].trigger_reason)) {
5686 			hdd_err("%s put fail",
5687 				"VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON");
5688 			wlan_cfg80211_vendor_free_skb(vendor_event);
5689 			return;
5690 		}
5691 	}
5692 	if (roam_stats->roam_event_param.roam_invoke_fail_reason) {
5693 		roam_event_type |=
5694 			QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON;
5695 		if (nla_put_u32(vendor_event, ROAM_INVOKE_FAIL_REASON,
5696 				roam_stats->
5697 				roam_event_param.roam_invoke_fail_reason)) {
5698 			hdd_err("%s put fail",
5699 				"VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON");
5700 			wlan_cfg80211_vendor_free_skb(vendor_event);
5701 			return;
5702 		}
5703 		roam_stats->roam_event_param.roam_invoke_fail_reason =
5704 						ROAM_EVENT_RT_INFO_RESET;
5705 	}
5706 	if (roam_stats->result[idx].present &&
5707 	    roam_stats->result[idx].fail_reason)
5708 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON;
5709 
5710 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE,
5711 			roam_event_type)) {
5712 		hdd_err("%s put fail", "QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE");
5713 			wlan_cfg80211_vendor_free_skb(vendor_event);
5714 		return;
5715 	}
5716 
5717 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5718 }
5719 
5720 #undef SUBCMD_ROAM_EVENTS_INDEX
5721 #undef ROAM_SCAN_FREQ_LIST
5722 #undef ROAM_INVOKE_FAIL_REASON
5723 #undef ROAM_SCAN_STATE
5724 #undef ROAM_EVENTS_CANDIDATE
5725 #undef CANDIDATE_BSSID
5726 #undef CANDIDATE_RSSI
5727 #undef CANDIDATE_FREQ
5728 #undef ROAM_FAIL_REASON
5729 #endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */
5730 
5731 #ifdef LINKSPEED_DEBUG_ENABLED
5732 #define linkspeed_dbg(format, args...) pr_info(format, ## args)
5733 #else
5734 #define linkspeed_dbg(format, args...)
5735 #endif /* LINKSPEED_DEBUG_ENABLED */
5736 
5737 static void
wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo * stats,struct station_info * info,struct wlan_hdd_link_info * link_info)5738 wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo *stats,
5739 				     struct station_info *info,
5740 				     struct wlan_hdd_link_info *link_info)
5741 {
5742 	uint8_t i;
5743 	uint32_t orig_cnt;
5744 	uint32_t orig_fail_cnt;
5745 	QDF_STATUS status;
5746 	uint8_t *peer_mac;
5747 	ol_txrx_soc_handle soc;
5748 	struct cdp_peer_stats *peer_stats;
5749 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
5750 
5751 	if (wlan_hdd_validate_context(hdd_ctx))
5752 		return;
5753 
5754 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
5755 		return;
5756 
5757 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
5758 	if (!peer_stats)
5759 		return;
5760 
5761 	soc = cds_get_context(QDF_MODULE_ID_SOC);
5762 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
5763 	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
5764 						 peer_mac, peer_stats,
5765 						 CDP_WILD_PEER_TYPE,
5766 						 WLAN_MAX_MLD);
5767 
5768 	if (QDF_IS_STATUS_ERROR(status)) {
5769 		hdd_err("Unable to get per link peer stats for the peer: "
5770 			QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_mac));
5771 		goto exit;
5772 	}
5773 
5774 	info->tx_retries = 0;
5775 	info->tx_failed = 0;
5776 
5777 	for (i = 0; i < WIFI_MAX_AC; ++i) {
5778 		info->tx_retries += stats->multiple_retry_cnt[i];
5779 		info->tx_failed += stats->fail_cnt[i];
5780 	}
5781 
5782 	orig_cnt = info->tx_retries;
5783 	orig_fail_cnt = info->tx_failed;
5784 	info->tx_retries = peer_stats->tx.retries_mpdu;
5785 	info->tx_failed += peer_stats->tx.mpdu_success_with_retries;
5786 	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx retries adjust from %d to %d",
5787 		  QDF_MAC_ADDR_REF(peer_mac), orig_cnt, info->tx_retries);
5788 	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx failed adjust from %d to %d",
5789 		  QDF_MAC_ADDR_REF(peer_mac), orig_fail_cnt, info->tx_failed);
5790 exit:
5791 	qdf_mem_free(peer_stats);
5792 }
5793 
5794 /**
5795  * wlan_hdd_fill_summary_stats() - populate station_info summary stats
5796  * @stats: summary stats to use as a source
5797  * @info: kernel station_info struct to use as a destination
5798  * @vdev_id: stats get from which vdev id
5799  *
5800  * Return: None
5801  */
wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo * stats,struct station_info * info,uint8_t vdev_id)5802 static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
5803 					struct station_info *info,
5804 					uint8_t vdev_id)
5805 {
5806 	int i;
5807 	struct cds_vdev_dp_stats dp_stats;
5808 	uint32_t orig_cnt;
5809 	uint32_t orig_fail_cnt;
5810 
5811 	info->rx_packets = stats->rx_frm_cnt;
5812 	info->tx_packets = 0;
5813 	info->tx_retries = 0;
5814 	info->tx_failed = 0;
5815 
5816 	for (i = 0; i < WIFI_MAX_AC; ++i) {
5817 		info->tx_packets += stats->tx_frm_cnt[i];
5818 		info->tx_retries += stats->multiple_retry_cnt[i];
5819 		info->tx_failed += stats->fail_cnt[i];
5820 	}
5821 
5822 	if (cds_dp_get_vdev_stats(vdev_id, &dp_stats)) {
5823 		orig_cnt = info->tx_retries;
5824 		orig_fail_cnt = info->tx_failed;
5825 		info->tx_retries = dp_stats.tx_retries_mpdu;
5826 		info->tx_failed += dp_stats.tx_mpdu_success_with_retries;
5827 		hdd_debug("vdev %d tx retries adjust from %d to %d",
5828 			  vdev_id, orig_cnt, info->tx_retries);
5829 		hdd_debug("tx failed adjust from %d to %d",
5830 			  orig_fail_cnt, info->tx_failed);
5831 	}
5832 
5833 	info->filled |= HDD_INFO_TX_PACKETS |
5834 			HDD_INFO_TX_RETRIES |
5835 			HDD_INFO_TX_FAILED;
5836 }
5837 
5838 /**
5839  * wlan_hdd_get_sap_stats() - get aggregate SAP stats
5840  * @link_info: Link info pointer in HDD adapter
5841  * @info: kernel station_info struct to populate
5842  *
5843  * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
5844  * support "station dump" and "station get" for SAP vdevs, even though they
5845  * aren't technically stations.
5846  *
5847  * Return: errno
5848  */
wlan_hdd_get_sap_stats(struct wlan_hdd_link_info * link_info,struct station_info * info)5849 static int wlan_hdd_get_sap_stats(struct wlan_hdd_link_info *link_info,
5850 				  struct station_info *info)
5851 {
5852 	int ret;
5853 
5854 	ret = wlan_hdd_get_station_stats(link_info);
5855 	if (ret) {
5856 		hdd_err("Failed to get SAP stats; status:%d", ret);
5857 		return ret;
5858 	}
5859 
5860 	wlan_hdd_fill_summary_stats(&link_info->hdd_stats.summary_stat,
5861 				    info, link_info->vdev_id);
5862 
5863 	return 0;
5864 }
5865 
5866 /**
5867  * hdd_get_max_rate_legacy() - get max rate for legacy mode
5868  * @stainfo: stainfo pointer
5869  * @rssidx: rssi index
5870  *
5871  * This function will get max rate for legacy mode
5872  *
5873  * Return: max rate on success, otherwise 0
5874  */
hdd_get_max_rate_legacy(struct hdd_station_info * stainfo,uint8_t rssidx)5875 static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
5876 					uint8_t rssidx)
5877 {
5878 	uint32_t maxrate = 0;
5879 	/*Minimum max rate, 6Mbps*/
5880 	int maxidx = 12;
5881 	int i;
5882 
5883 	/* check supported rates */
5884 	if (stainfo->max_supp_idx != 0xff &&
5885 	    maxidx < stainfo->max_supp_idx)
5886 		maxidx = stainfo->max_supp_idx;
5887 
5888 	/* check extended rates */
5889 	if (stainfo->max_ext_idx != 0xff &&
5890 	    maxidx < stainfo->max_ext_idx)
5891 		maxidx = stainfo->max_ext_idx;
5892 
5893 	for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) {
5894 		if (supported_data_rate[i].beacon_rate_index == maxidx)
5895 			maxrate =
5896 				supported_data_rate[i].supported_rate[rssidx];
5897 	}
5898 
5899 	hdd_debug("maxrate %d", maxrate);
5900 
5901 	return maxrate;
5902 }
5903 
5904 /**
5905  * hdd_get_max_rate_ht() - get max rate for ht mode
5906  * @stainfo: stainfo pointer
5907  * @stats: fw txrx status pointer
5908  * @rate_flags: rate flags
5909  * @nss: number of streams
5910  * @maxrate: returned max rate buffer pointer
5911  * @max_mcs_idx: max mcs idx
5912  * @report_max: report max rate or actual rate
5913  *
5914  * This function will get max rate for ht mode
5915  *
5916  * Return: None
5917  */
hdd_get_max_rate_ht(struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats,uint32_t rate_flags,uint8_t nss,uint32_t * maxrate,uint8_t * max_mcs_idx,bool report_max)5918 static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
5919 				struct hdd_fw_txrx_stats *stats,
5920 				uint32_t rate_flags,
5921 				uint8_t nss,
5922 				uint32_t *maxrate,
5923 				uint8_t *max_mcs_idx,
5924 				bool report_max)
5925 {
5926 	struct index_data_rate_type *supported_mcs_rate;
5927 	uint32_t tmprate;
5928 	uint8_t flag = 0, mcsidx;
5929 	int8_t rssi = stats->rssi;
5930 	int mode;
5931 	int i;
5932 
5933 	if (rate_flags & TX_RATE_HT40)
5934 		mode = 1;
5935 	else
5936 		mode = 0;
5937 
5938 	if (rate_flags & TX_RATE_HT40)
5939 		flag |= 1;
5940 	if (rate_flags & TX_RATE_SGI)
5941 		flag |= 2;
5942 
5943 	supported_mcs_rate = (struct index_data_rate_type *)
5944 		((nss == 1) ? &supported_mcs_rate_nss1 :
5945 		 &supported_mcs_rate_nss2);
5946 
5947 	if (stainfo->max_mcs_idx == 0xff) {
5948 		hdd_err("invalid max_mcs_idx");
5949 		/* report real mcs idx */
5950 		mcsidx = stats->tx_rate.mcs;
5951 	} else {
5952 		mcsidx = stainfo->max_mcs_idx;
5953 	}
5954 
5955 	if (!report_max) {
5956 		for (i = 0; i < MAX_HT_MCS_INDEX && i < mcsidx; i++) {
5957 			if (rssi <= rssi_mcs_tbl[mode][i]) {
5958 				mcsidx = i;
5959 				break;
5960 			}
5961 		}
5962 		if (mcsidx < stats->tx_rate.mcs &&
5963 		    stats->tx_rate.mcs <= MAX_HT_MCS_INDEX)
5964 			mcsidx = stats->tx_rate.mcs;
5965 	}
5966 
5967 	if (mcsidx > MAX_HT_MCS_INDEX)
5968 		mcsidx = MAX_HT_MCS_INDEX;
5969 	tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
5970 
5971 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
5972 
5973 	*maxrate = tmprate;
5974 	*max_mcs_idx = mcsidx;
5975 }
5976 
5977 /**
5978  * hdd_get_max_rate_vht() - get max rate for vht mode
5979  * @stainfo: stainfo pointer
5980  * @stats: fw txrx status pointer
5981  * @rate_flags: rate flags
5982  * @nss: number of streams
5983  * @maxrate: returned max rate buffer pointer
5984  * @max_mcs_idx: max mcs idx
5985  * @report_max: report max rate or actual rate
5986  *
5987  * This function will get max rate for vht mode
5988  *
5989  * Return: None
5990  */
hdd_get_max_rate_vht(struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats,uint32_t rate_flags,uint8_t nss,uint32_t * maxrate,uint8_t * max_mcs_idx,bool report_max)5991 static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
5992 				 struct hdd_fw_txrx_stats *stats,
5993 				 uint32_t rate_flags,
5994 				 uint8_t nss,
5995 				 uint32_t *maxrate,
5996 				 uint8_t *max_mcs_idx,
5997 				 bool report_max)
5998 {
5999 	struct index_vht_data_rate_type *supported_vht_mcs_rate;
6000 	uint32_t tmprate = 0;
6001 	uint32_t vht_max_mcs;
6002 	uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
6003 	int8_t rssi = stats->rssi;
6004 	int mode;
6005 	int i;
6006 
6007 	supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
6008 		((nss == 1) ?
6009 		 &supported_vht_mcs_rate_nss1 :
6010 		 &supported_vht_mcs_rate_nss2);
6011 
6012 	if (rate_flags & TX_RATE_VHT80)
6013 		mode = 2;
6014 	else if (rate_flags & TX_RATE_VHT40)
6015 		mode = 1;
6016 	else
6017 		mode = 0;
6018 
6019 	if (rate_flags &
6020 	    (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) {
6021 		vht_max_mcs =
6022 			(enum data_rate_11ac_max_mcs)
6023 			(stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
6024 		if (rate_flags & TX_RATE_SGI)
6025 			flag |= 1;
6026 
6027 		if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
6028 			mcsidx = 7;
6029 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
6030 			mcsidx = 8;
6031 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
6032 			/*
6033 			 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
6034 			 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
6035 			 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
6036 			 */
6037 			if ((rate_flags & TX_RATE_VHT20) &&
6038 			    (nss != 3 && nss != 6))
6039 				mcsidx = 8;
6040 			else
6041 				mcsidx = 9;
6042 		} else {
6043 			hdd_err("invalid vht_max_mcs");
6044 			/* report real mcs idx */
6045 			mcsidx = stats->tx_rate.mcs;
6046 		}
6047 
6048 		if (!report_max) {
6049 			for (i = 0; i <= mcsidx && i < MAX_RSSI_MCS_INDEX; i++) {
6050 				if (rssi <= rssi_mcs_tbl[mode][i]) {
6051 					mcsidx = i;
6052 					break;
6053 				}
6054 			}
6055 			if (mcsidx < stats->tx_rate.mcs)
6056 				mcsidx = stats->tx_rate.mcs;
6057 		}
6058 
6059 		if (rate_flags & TX_RATE_VHT80)
6060 			tmprate =
6061 		    supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
6062 		else if (rate_flags & TX_RATE_VHT40)
6063 			tmprate =
6064 		    supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
6065 		else if (rate_flags & TX_RATE_VHT20)
6066 			tmprate =
6067 		    supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
6068 	}
6069 
6070 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
6071 
6072 	*maxrate = tmprate;
6073 	*max_mcs_idx = mcsidx;
6074 }
6075 
6076 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
6077 #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
hdd_fill_eht_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6078 static bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
6079 				enum tx_rate_info rate_flags,
6080 				uint8_t mcsidx,
6081 				uint8_t nss,
6082 				uint8_t rate_info_flag)
6083 {
6084 	if (rate_info_flag == RATE_INFO_FLAGS_EHT_MCS) {
6085 		rate_info->nss = nss;
6086 		rate_info->mcs = mcsidx;
6087 		rate_info->flags |= RATE_INFO_FLAGS_EHT_MCS;
6088 		if (rate_flags & TX_RATE_EHT320)
6089 			rate_info->bw = RATE_INFO_BW_320;
6090 		else if (rate_flags & TX_RATE_EHT160)
6091 			rate_info->bw = RATE_INFO_BW_160;
6092 		else if (rate_flags & TX_RATE_EHT80)
6093 			rate_info->bw = RATE_INFO_BW_80;
6094 		else if (rate_flags & TX_RATE_EHT40)
6095 			rate_info->bw = RATE_INFO_BW_40;
6096 		else if (rate_flags & TX_RATE_EHT20)
6097 			rate_info->bw = RATE_INFO_BW_20;
6098 
6099 		return true;
6100 	}
6101 
6102 	return false;
6103 }
6104 #else
hdd_fill_eht_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6105 static inline bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
6106 				       enum tx_rate_info rate_flags,
6107 				       uint8_t mcsidx,
6108 				       uint8_t nss,
6109 				       uint8_t rate_info_flag)
6110 {
6111 	return false;
6112 }
6113 #endif
6114 /**
6115  * hdd_fill_bw_mcs() - fill ch width and mcs flags
6116  * @rate_info: pointer to struct rate_info
6117  * @rate_flags: HDD rate flags
6118  * @mcsidx: mcs index
6119  * @nss: number of streams
6120  * @rate_info_flag: rate info flags
6121  *
6122  * This function will fill ch width and mcs flags
6123  *
6124  * Return: None
6125  */
hdd_fill_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6126 static void hdd_fill_bw_mcs(struct rate_info *rate_info,
6127 			    enum tx_rate_info rate_flags,
6128 			    uint8_t mcsidx,
6129 			    uint8_t nss,
6130 			    uint8_t rate_info_flag)
6131 {
6132 	if (hdd_fill_eht_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6133 				rate_info_flag))
6134 		return;
6135 
6136 	if (rate_info_flag == RATE_INFO_FLAGS_HE_MCS) {
6137 		rate_info->nss = nss;
6138 		rate_info->mcs = mcsidx;
6139 		rate_info->flags |= RATE_INFO_FLAGS_HE_MCS;
6140 		if (rate_flags & TX_RATE_HE160)
6141 			rate_info->bw = RATE_INFO_BW_160;
6142 		else if (rate_flags & TX_RATE_HE80)
6143 			rate_info->bw = RATE_INFO_BW_80;
6144 		else if (rate_flags & TX_RATE_HE40)
6145 			rate_info->bw = RATE_INFO_BW_40;
6146 		else if (rate_flags & TX_RATE_HE20)
6147 			rate_info->bw = RATE_INFO_BW_20;
6148 	} else if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) {
6149 		rate_info->nss = nss;
6150 		rate_info->mcs = mcsidx;
6151 		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
6152 		if (rate_flags & TX_RATE_VHT160)
6153 			rate_info->bw = RATE_INFO_BW_160;
6154 		else if (rate_flags & TX_RATE_VHT80)
6155 			rate_info->bw = RATE_INFO_BW_80;
6156 		else if (rate_flags & TX_RATE_VHT40)
6157 			rate_info->bw = RATE_INFO_BW_40;
6158 		else if (rate_flags & TX_RATE_VHT20)
6159 			rate_info->bw = RATE_INFO_BW_20;
6160 	} else {
6161 		rate_info->mcs = (nss - 1) << 3;
6162 		rate_info->mcs |= mcsidx;
6163 		rate_info->flags |= RATE_INFO_FLAGS_MCS;
6164 		if (rate_flags & TX_RATE_HT40)
6165 			rate_info->bw = RATE_INFO_BW_40;
6166 	}
6167 }
6168 #else
6169 /**
6170  * hdd_fill_bw_mcs() - fill ch width and mcs flags
6171  * @rate_info: pointer to struct rate_info
6172  * @rate_flags: HDD rate flags
6173  * @mcsidx: mcs index
6174  * @nss: number of streams
6175  * @rate_info_flag: rate info flags
6176  *
6177  * This function will fill ch width and mcs flags
6178  *
6179  * Return: None
6180  */
hdd_fill_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6181 static void hdd_fill_bw_mcs(struct rate_info *rate_info,
6182 			    enum tx_rate_info rate_flags,
6183 			    uint8_t mcsidx,
6184 			    uint8_t nss,
6185 			    uint8_t rate_info_flag)
6186 {
6187 	if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) {
6188 		rate_info->nss = nss;
6189 		rate_info->mcs = mcsidx;
6190 		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
6191 		if (rate_flags & TX_RATE_VHT80)
6192 			rate_info->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
6193 		else if (rate_flags & TX_RATE_VHT40)
6194 			rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
6195 		else if (rate_flags & TX_RATE_VHT20)
6196 			rate_info->bw = RATE_INFO_BW_20;
6197 	} else {
6198 		rate_info->mcs = (nss - 1) << 3;
6199 		rate_info->mcs |= mcsidx;
6200 		rate_info->flags |= RATE_INFO_FLAGS_MCS;
6201 		if (rate_flags & TX_RATE_HT40)
6202 			rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
6203 	}
6204 }
6205 #endif
6206 
6207 #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
hdd_fill_sinfo_eht_rate_info(struct rate_info * rate_info,uint32_t rate_flags,uint8_t mcsidx,uint8_t nss)6208 static void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
6209 					 uint32_t rate_flags, uint8_t mcsidx,
6210 					 uint8_t nss)
6211 {
6212 	if (rate_flags &
6213 			(TX_RATE_EHT320 |
6214 			 TX_RATE_EHT160 |
6215 			 TX_RATE_EHT80 |
6216 			 TX_RATE_EHT40 |
6217 			 TX_RATE_EHT20)) {
6218 		hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6219 				RATE_INFO_FLAGS_EHT_MCS);
6220 	}
6221 }
6222 #else
hdd_fill_sinfo_eht_rate_info(struct rate_info * rate_info,uint32_t rate_flags,uint8_t mcsidx,uint8_t nss)6223 static inline void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
6224 						uint32_t rate_flags,
6225 						uint8_t mcsidx,
6226 						uint8_t nss)
6227 {
6228 }
6229 #endif
6230 
6231 /**
6232  * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
6233  * @sinfo: pointer to struct station_info
6234  * @rate_flags: HDD rate flags
6235  * @mcsidx: mcs index
6236  * @nss: number of streams
6237  * @rate: data rate (kbps)
6238  * @is_tx: flag to indicate whether it is tx or rx
6239  *
6240  * This function will fill rate info of sinfo struct
6241  *
6242  * Return: None
6243  */
hdd_fill_sinfo_rate_info(struct station_info * sinfo,uint32_t rate_flags,uint8_t mcsidx,uint8_t nss,uint32_t rate,bool is_tx)6244 static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
6245 				     uint32_t rate_flags,
6246 				     uint8_t mcsidx,
6247 				     uint8_t nss,
6248 				     uint32_t rate,
6249 				     bool is_tx)
6250 {
6251 	struct rate_info *rate_info;
6252 
6253 	if (is_tx)
6254 		rate_info = &sinfo->txrate;
6255 	else
6256 		rate_info = &sinfo->rxrate;
6257 
6258 	if (rate_flags & TX_RATE_LEGACY) {
6259 		/* provide to the UI in units of 100kbps */
6260 		rate_info->legacy = rate;
6261 	} else {
6262 		/* must be MCS */
6263 		hdd_fill_sinfo_eht_rate_info(rate_info, rate_flags, mcsidx,
6264 					     nss);
6265 
6266 		if (rate_flags &
6267 				(TX_RATE_HE160 |
6268 				 TX_RATE_HE80 |
6269 				 TX_RATE_HE40 |
6270 				 TX_RATE_HE20)) {
6271 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6272 					RATE_INFO_FLAGS_HE_MCS);
6273 		}
6274 		if (rate_flags &
6275 				(TX_RATE_VHT160 |
6276 				 TX_RATE_VHT80 |
6277 				 TX_RATE_VHT40 |
6278 				 TX_RATE_VHT20)) {
6279 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6280 					RATE_INFO_FLAGS_VHT_MCS);
6281 		}
6282 		if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
6283 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6284 					RATE_INFO_FLAGS_MCS);
6285 		}
6286 		if (rate_flags & TX_RATE_SGI) {
6287 			if (!(rate_info->flags & RATE_INFO_FLAGS_VHT_MCS))
6288 				rate_info->flags |= RATE_INFO_FLAGS_MCS;
6289 			rate_info->flags |= RATE_INFO_FLAGS_SHORT_GI;
6290 		}
6291 	}
6292 
6293 	hdd_debug("flag %x mcs %d legacy %d nss %d",
6294 		  rate_info->flags,
6295 		  rate_info->mcs,
6296 		  rate_info->legacy,
6297 		  rate_info->nss);
6298 
6299 	if (is_tx)
6300 		sinfo->filled |= HDD_INFO_TX_BITRATE;
6301 	else
6302 		sinfo->filled |= HDD_INFO_RX_BITRATE;
6303 }
6304 
6305 /**
6306  * hdd_fill_sta_flags() - fill sta flags of sinfo
6307  * @sinfo: station_info struct pointer
6308  * @stainfo: stainfo pointer
6309  *
6310  * This function will fill sta flags of sinfo
6311  *
6312  * Return: None
6313  */
hdd_fill_sta_flags(struct station_info * sinfo,struct hdd_station_info * stainfo)6314 static void hdd_fill_sta_flags(struct station_info *sinfo,
6315 			       struct hdd_station_info *stainfo)
6316 {
6317 	sinfo->sta_flags.mask = NL80211_STA_FLAG_WME;
6318 
6319 	if (stainfo->is_qos_enabled)
6320 		sinfo->sta_flags.set |= NL80211_STA_FLAG_WME;
6321 	else
6322 		sinfo->sta_flags.set &= ~NL80211_STA_FLAG_WME;
6323 
6324 	sinfo->filled |= HDD_INFO_STA_FLAGS;
6325 }
6326 
6327 /**
6328  * hdd_fill_per_chain_avg_signal() - fill per chain avg rssi of sinfo
6329  * @sinfo: station_info struct pointer
6330  * @stainfo: stainfo pointer
6331  *
6332  * This function will fill per chain avg rssi of sinfo
6333  *
6334  * Return: None
6335  */
hdd_fill_per_chain_avg_signal(struct station_info * sinfo,struct hdd_station_info * stainfo)6336 static void hdd_fill_per_chain_avg_signal(struct station_info *sinfo,
6337 					  struct hdd_station_info *stainfo)
6338 {
6339 	bool rssi_stats_valid = false;
6340 	uint8_t i;
6341 
6342 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
6343 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
6344 		sinfo->chain_signal_avg[i] = stainfo->peer_rssi_per_chain[i];
6345 		sinfo->chains |= 1 << i;
6346 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
6347 		    sinfo->chain_signal_avg[i] != 0)
6348 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
6349 
6350 		if (sinfo->chain_signal_avg[i])
6351 			rssi_stats_valid = true;
6352 	}
6353 
6354 	if (rssi_stats_valid) {
6355 		sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
6356 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
6357 	}
6358 }
6359 
6360 /**
6361  * hdd_fill_rate_info() - fill rate info of sinfo
6362  * @psoc: psoc context
6363  * @sinfo: station_info struct pointer
6364  * @stainfo: stainfo pointer
6365  * @stats: fw txrx status pointer
6366  *
6367  * This function will fill rate info of sinfo
6368  *
6369  * Return: None
6370  */
hdd_fill_rate_info(struct wlan_objmgr_psoc * psoc,struct station_info * sinfo,struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats)6371 static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc,
6372 			       struct station_info *sinfo,
6373 			       struct hdd_station_info *stainfo,
6374 			       struct hdd_fw_txrx_stats *stats)
6375 {
6376 	enum tx_rate_info rate_flags;
6377 	uint8_t mcsidx = 0xff;
6378 	uint32_t tx_rate, rx_rate, maxrate, tmprate;
6379 	int rssidx;
6380 	int nss = 1;
6381 	int link_speed_rssi_high = 0;
6382 	int link_speed_rssi_mid = 0;
6383 	int link_speed_rssi_low = 0;
6384 	uint32_t link_speed_rssi_report = 0;
6385 
6386 	ucfg_mlme_stats_get_cfg_values(psoc,
6387 				       &link_speed_rssi_high,
6388 				       &link_speed_rssi_mid,
6389 				       &link_speed_rssi_low,
6390 				       &link_speed_rssi_report);
6391 
6392 	hdd_debug("reportMaxLinkSpeed %d", link_speed_rssi_report);
6393 
6394 	/* convert to 100kbps expected in rate table */
6395 	tx_rate = stats->tx_rate.rate / 100;
6396 	rate_flags = stainfo->rate_flags;
6397 	if (!(rate_flags & TX_RATE_LEGACY)) {
6398 		nss = stainfo->nss;
6399 		if (ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
6400 			/* Get current rate flags if report actual */
6401 			if (stats->tx_rate.rate_flags)
6402 				rate_flags =
6403 					stats->tx_rate.rate_flags;
6404 			nss = stats->tx_rate.nss;
6405 		}
6406 
6407 		if (stats->tx_rate.mcs == INVALID_MCS_IDX)
6408 			rate_flags = TX_RATE_LEGACY;
6409 	}
6410 
6411 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
6412 		/* we do not want to necessarily report the current speed */
6413 		if (ucfg_mlme_stats_is_link_speed_report_max(psoc)) {
6414 			/* report the max possible speed */
6415 			rssidx = 0;
6416 		} else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
6417 					psoc)) {
6418 			/* report the max possible speed with RSSI scaling */
6419 			if (stats->rssi >= link_speed_rssi_high) {
6420 				/* report the max possible speed */
6421 				rssidx = 0;
6422 			} else if (stats->rssi >= link_speed_rssi_mid) {
6423 				/* report middle speed */
6424 				rssidx = 1;
6425 			} else if (stats->rssi >= link_speed_rssi_low) {
6426 				/* report low speed */
6427 				rssidx = 2;
6428 			} else {
6429 				/* report actual speed */
6430 				rssidx = 3;
6431 			}
6432 		} else {
6433 			/* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
6434 			hdd_err("Invalid value for reportMaxLinkSpeed: %u",
6435 				link_speed_rssi_report);
6436 			rssidx = 0;
6437 		}
6438 
6439 		maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
6440 
6441 		/*
6442 		 * Get MCS Rate Set --
6443 		 * Only if we are connected in non legacy mode and not
6444 		 * reporting actual speed
6445 		 */
6446 		if ((rssidx != 3) &&
6447 		    !(rate_flags & TX_RATE_LEGACY)) {
6448 			hdd_get_max_rate_vht(stainfo,
6449 					     stats,
6450 					     rate_flags,
6451 					     nss,
6452 					     &tmprate,
6453 					     &mcsidx,
6454 					     rssidx == 0);
6455 
6456 			if (maxrate < tmprate &&
6457 			    mcsidx != INVALID_MCS_IDX)
6458 				maxrate = tmprate;
6459 
6460 			if (mcsidx == INVALID_MCS_IDX)
6461 				hdd_get_max_rate_ht(stainfo,
6462 						    stats,
6463 						    rate_flags,
6464 						    nss,
6465 						    &tmprate,
6466 						    &mcsidx,
6467 						    rssidx == 0);
6468 
6469 			if (maxrate < tmprate &&
6470 			    mcsidx != INVALID_MCS_IDX)
6471 				maxrate = tmprate;
6472 		} else if (!(rate_flags & TX_RATE_LEGACY)) {
6473 			maxrate = tx_rate;
6474 			mcsidx = stats->tx_rate.mcs;
6475 		}
6476 
6477 		/*
6478 		 * make sure we report a value at least as big as our
6479 		 * current rate
6480 		 */
6481 		if (maxrate < tx_rate || maxrate == 0) {
6482 			maxrate = tx_rate;
6483 			if (!(rate_flags & TX_RATE_LEGACY)) {
6484 				mcsidx = stats->tx_rate.mcs;
6485 				/*
6486 				 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
6487 				 * - MCS9 is valid for VHT20 when Nss = 3 or
6488 				 *   Nss = 6
6489 				 * - MCS9 is not valid for VHT20 when
6490 				 *   Nss = 1,2,4,5,7,8
6491 				 */
6492 				if ((rate_flags & TX_RATE_VHT20) &&
6493 				    (mcsidx > 8) &&
6494 				    (nss != 3 && nss != 6))
6495 					mcsidx = 8;
6496 			}
6497 		}
6498 	} else {
6499 		/* report current rate instead of max rate */
6500 		maxrate = tx_rate;
6501 		if (!(rate_flags & TX_RATE_LEGACY))
6502 			mcsidx = stats->tx_rate.mcs;
6503 	}
6504 
6505 	hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss,
6506 				 maxrate, true);
6507 
6508 	/* convert to 100kbps expected in rate table */
6509 	rx_rate = stats->rx_rate.rate / 100;
6510 
6511 	/* report current rx rate*/
6512 	rate_flags = stainfo->rate_flags;
6513 	if (!(rate_flags & TX_RATE_LEGACY)) {
6514 		if (stats->rx_rate.rate_flags)
6515 			rate_flags = stats->rx_rate.rate_flags;
6516 		nss = stats->rx_rate.nss;
6517 		if (stats->rx_rate.mcs == INVALID_MCS_IDX)
6518 			rate_flags = TX_RATE_LEGACY;
6519 	}
6520 	if (!(rate_flags & TX_RATE_LEGACY))
6521 		mcsidx = stats->rx_rate.mcs;
6522 
6523 	hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss,
6524 				 rx_rate, false);
6525 
6526 	sinfo->expected_throughput = stainfo->max_phy_rate;
6527 	sinfo->filled |= HDD_INFO_EXPECTED_THROUGHPUT;
6528 }
6529 
6530 /**
6531  * wlan_hdd_fill_station_info() - fill station_info struct
6532  * @psoc: psoc context
6533  * @adapter: The HDD adapter structure
6534  * @sinfo: station_info struct pointer
6535  * @stainfo: stainfo pointer
6536  * @stats: fw txrx status pointer
6537  *
6538  * This function will fill station_info struct
6539  *
6540  * Return: None
6541  */
wlan_hdd_fill_station_info(struct wlan_objmgr_psoc * psoc,struct hdd_adapter * adapter,struct station_info * sinfo,struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats)6542 static void wlan_hdd_fill_station_info(struct wlan_objmgr_psoc *psoc,
6543 				       struct hdd_adapter *adapter,
6544 				       struct station_info *sinfo,
6545 				       struct hdd_station_info *stainfo,
6546 				       struct hdd_fw_txrx_stats *stats)
6547 {
6548 	qdf_time_t curr_time, dur;
6549 	struct cdp_peer_stats *peer_stats;
6550 	QDF_STATUS status;
6551 
6552 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
6553 	if (!peer_stats)
6554 		return;
6555 
6556 	status =
6557 		cdp_host_get_peer_stats(cds_get_context(QDF_MODULE_ID_SOC),
6558 					adapter->deflink->vdev_id,
6559 					stainfo->sta_mac.bytes,
6560 					peer_stats);
6561 
6562 	if (QDF_IS_STATUS_ERROR(status)) {
6563 		hdd_err("cdp_host_get_peer_stats failed. error: %u", status);
6564 		qdf_mem_free(peer_stats);
6565 		return;
6566 	}
6567 
6568 	stainfo->last_tx_rx_ts =
6569 		peer_stats->tx.last_tx_ts > peer_stats->rx.last_rx_ts ?
6570 		peer_stats->tx.last_tx_ts : peer_stats->rx.last_rx_ts;
6571 
6572 	qdf_mem_free(peer_stats);
6573 
6574 	curr_time = qdf_system_ticks();
6575 	dur = curr_time - stainfo->assoc_ts;
6576 	sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
6577 	sinfo->filled |= HDD_INFO_CONNECTED_TIME;
6578 	dur = curr_time - stainfo->last_tx_rx_ts;
6579 	sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
6580 	sinfo->filled |= HDD_INFO_INACTIVE_TIME;
6581 	sinfo->signal = stats->rssi;
6582 	sinfo->filled |= HDD_INFO_SIGNAL;
6583 	sinfo->tx_bytes = stats->tx_bytes;
6584 	sinfo->filled |= HDD_INFO_TX_BYTES | HDD_INFO_TX_BYTES64;
6585 	sinfo->tx_packets = stats->tx_packets;
6586 	sinfo->filled |= HDD_INFO_TX_PACKETS;
6587 	sinfo->rx_bytes = stats->rx_bytes;
6588 	sinfo->filled |= HDD_INFO_RX_BYTES | HDD_INFO_RX_BYTES64;
6589 	sinfo->rx_packets = stats->rx_packets;
6590 	sinfo->filled |= HDD_INFO_RX_PACKETS;
6591 	sinfo->tx_failed = stats->tx_failed;
6592 	sinfo->filled |= HDD_INFO_TX_FAILED;
6593 	sinfo->tx_retries = stats->tx_retries;
6594 
6595 	/* sta flags */
6596 	hdd_fill_sta_flags(sinfo, stainfo);
6597 
6598 	/* per chain avg rssi */
6599 	hdd_fill_per_chain_avg_signal(sinfo, stainfo);
6600 
6601 	/* tx / rx rate info */
6602 	hdd_fill_rate_info(psoc, sinfo, stainfo, stats);
6603 
6604 	/* assoc req ies */
6605 	sinfo->assoc_req_ies = stainfo->assoc_req_ies.ptr;
6606 	sinfo->assoc_req_ies_len = stainfo->assoc_req_ies.len;
6607 
6608 	/* dump sta info*/
6609 	hdd_debug("dump stainfo");
6610 	hdd_debug("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
6611 		  sinfo->connected_time, sinfo->inactive_time,
6612 		  sinfo->tx_packets, sinfo->rx_packets);
6613 	hdd_debug("failed %d retries %d tx_bytes %lld rx_bytes %lld",
6614 		  sinfo->tx_failed, sinfo->tx_retries,
6615 		  sinfo->tx_bytes, sinfo->rx_bytes);
6616 	hdd_debug("rssi %d tx mcs %d legacy %d nss %d flags %x",
6617 		  sinfo->signal, sinfo->txrate.mcs,
6618 		  sinfo->txrate.legacy, sinfo->txrate.nss,
6619 		  sinfo->txrate.flags);
6620 	hdd_debug("rx mcs %d legacy %d nss %d flags %x",
6621 		  sinfo->rxrate.mcs, sinfo->rxrate.legacy,
6622 		  sinfo->rxrate.nss, sinfo->rxrate.flags);
6623 }
6624 
6625 /**
6626  * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
6627  * @rate: Data rate (100 kbps)
6628  * @nss: Number of streams
6629  * @mcs: HT mcs index
6630  *
6631  * This function is used to construct HT rate flag with rate, nss and mcs
6632  *
6633  * Return: rate flags for success, 0 on failure.
6634  */
hdd_get_rate_flags_ht(uint32_t rate,uint8_t nss,uint8_t mcs)6635 static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
6636 				     uint8_t nss,
6637 				     uint8_t mcs)
6638 {
6639 	struct index_data_rate_type *mcs_rate;
6640 	uint8_t flags = 0;
6641 
6642 	mcs_rate = (struct index_data_rate_type *)
6643 		((nss == 1) ? &supported_mcs_rate_nss1 :
6644 		 &supported_mcs_rate_nss2);
6645 
6646 	if (rate == mcs_rate[mcs].supported_rate[0]) {
6647 		flags |= TX_RATE_HT20;
6648 	} else if (rate == mcs_rate[mcs].supported_rate[1]) {
6649 		flags |= TX_RATE_HT40;
6650 	} else if (rate == mcs_rate[mcs].supported_rate[2]) {
6651 		flags |= TX_RATE_HT20;
6652 		flags |= TX_RATE_SGI;
6653 	} else if (rate == mcs_rate[mcs].supported_rate[3]) {
6654 		flags |= TX_RATE_HT40;
6655 		flags |= TX_RATE_SGI;
6656 	} else {
6657 		hdd_err("invalid params rate %d nss %d mcs %d",
6658 			rate, nss, mcs);
6659 	}
6660 
6661 	return flags;
6662 }
6663 
6664 /**
6665  * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
6666  * @rate: Data rate (100 kbps)
6667  * @nss: Number of streams
6668  * @mcs: VHT mcs index
6669  *
6670  * This function is used to construct VHT rate flag with rate, nss and mcs
6671  *
6672  * Return: rate flags for success, 0 on failure.
6673  */
hdd_get_rate_flags_vht(uint32_t rate,uint8_t nss,uint8_t mcs)6674 static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
6675 				      uint8_t nss,
6676 				      uint8_t mcs)
6677 {
6678 	struct index_vht_data_rate_type *mcs_rate;
6679 	uint8_t flags = 0;
6680 
6681 	if (mcs >= ARRAY_SIZE(supported_vht_mcs_rate_nss1)) {
6682 		hdd_err("Invalid mcs index %d", mcs);
6683 		return flags;
6684 	}
6685 
6686 	mcs_rate = (struct index_vht_data_rate_type *)
6687 		((nss == 1) ?
6688 		 &supported_vht_mcs_rate_nss1 :
6689 		 &supported_vht_mcs_rate_nss2);
6690 
6691 	if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
6692 		flags |= TX_RATE_VHT80;
6693 	} else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
6694 		flags |= TX_RATE_VHT80;
6695 		flags |= TX_RATE_SGI;
6696 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
6697 		flags |= TX_RATE_VHT40;
6698 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
6699 		flags |= TX_RATE_VHT40;
6700 		flags |= TX_RATE_SGI;
6701 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
6702 		flags |= TX_RATE_VHT20;
6703 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
6704 		flags |= TX_RATE_VHT20;
6705 		flags |= TX_RATE_SGI;
6706 	} else {
6707 		hdd_err("invalid params rate %d nss %d mcs %d",
6708 			rate, nss, mcs);
6709 	}
6710 
6711 	return flags;
6712 }
6713 
6714 /**
6715  * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
6716  * @rate: Data rate (100 kbps)
6717  * @mode: Tx/Rx mode
6718  * @nss: Number of streams
6719  * @mcs: Mcs index
6720  *
6721  * This function is used to construct rate flag with rate, nss and mcs
6722  *
6723  * Return: rate flags for success, 0 on failure.
6724  */
hdd_get_rate_flags(uint32_t rate,uint8_t mode,uint8_t nss,uint8_t mcs)6725 static uint8_t hdd_get_rate_flags(uint32_t rate,
6726 				  uint8_t mode,
6727 				  uint8_t nss,
6728 				  uint8_t mcs)
6729 {
6730 	uint8_t flags = 0;
6731 
6732 	if (mode == SIR_SME_PHY_MODE_HT)
6733 		flags = hdd_get_rate_flags_ht(rate, nss, mcs);
6734 	else if (mode == SIR_SME_PHY_MODE_VHT)
6735 		flags = hdd_get_rate_flags_vht(rate, nss, mcs);
6736 	else
6737 		hdd_debug("invalid mode param %d", mode);
6738 
6739 	return flags;
6740 }
6741 
6742 /**
6743  * wlan_hdd_fill_rate_info() - fill HDD rate info from peer info
6744  * @txrx_stats: pointer to txrx stats to be filled with rate info
6745  * @peer_info: peer info pointer
6746  *
6747  * This function is used to fill HDD rate info from peer info
6748  *
6749  * Return: None
6750  */
wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats * txrx_stats,struct peer_stats_info_ext_event * peer_info)6751 static void wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats *txrx_stats,
6752 				    struct peer_stats_info_ext_event *peer_info)
6753 {
6754 	uint8_t flags;
6755 	uint32_t rate_code;
6756 
6757 	/* tx rate info */
6758 	txrx_stats->tx_rate.rate = peer_info->tx_rate;
6759 	rate_code = peer_info->tx_rate_code;
6760 
6761 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6762 			WMI_RATE_PREAMBLE_HT)
6763 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_HT;
6764 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6765 			WMI_RATE_PREAMBLE_VHT)
6766 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_VHT;
6767 	else
6768 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
6769 
6770 	txrx_stats->tx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
6771 	txrx_stats->tx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
6772 
6773 	flags = hdd_get_rate_flags(txrx_stats->tx_rate.rate / 100,
6774 				   txrx_stats->tx_rate.mode,
6775 				   txrx_stats->tx_rate.nss,
6776 				   txrx_stats->tx_rate.mcs);
6777 
6778 	txrx_stats->tx_rate.rate_flags = flags;
6779 
6780 	hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
6781 		  txrx_stats->tx_rate.mode,
6782 		  txrx_stats->tx_rate.nss,
6783 		  txrx_stats->tx_rate.mcs,
6784 		  txrx_stats->tx_rate.rate_flags,
6785 		  flags);
6786 
6787 	/* rx rate info */
6788 	txrx_stats->rx_rate.rate = peer_info->rx_rate;
6789 	rate_code = peer_info->rx_rate_code;
6790 
6791 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6792 			WMI_RATE_PREAMBLE_HT)
6793 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_HT;
6794 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6795 			WMI_RATE_PREAMBLE_VHT)
6796 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_VHT;
6797 	else
6798 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
6799 
6800 	txrx_stats->rx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
6801 	txrx_stats->rx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
6802 
6803 	flags = hdd_get_rate_flags(txrx_stats->rx_rate.rate / 100,
6804 				   txrx_stats->rx_rate.mode,
6805 				   txrx_stats->rx_rate.nss,
6806 				   txrx_stats->rx_rate.mcs);
6807 
6808 	txrx_stats->rx_rate.rate_flags = flags;
6809 
6810 	hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
6811 		 txrx_stats->rx_rate.mode,
6812 		 txrx_stats->rx_rate.nss,
6813 		 txrx_stats->rx_rate.mcs,
6814 		 txrx_stats->rx_rate.rate_flags,
6815 		 flags);
6816 }
6817 
6818 /**
6819  * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
6820  * @wiphy: pointer to wiphy
6821  * @dev: pointer to net_device structure
6822  * @stainfo: request peer station info
6823  * @sinfo: pointer to station_info struct
6824  *
6825  * This function will get remote peer info from fw and fill sinfo struct
6826  *
6827  * Return: 0 on success, otherwise error value
6828  */
wlan_hdd_get_station_remote(struct wiphy * wiphy,struct net_device * dev,struct hdd_station_info * stainfo,struct station_info * sinfo)6829 static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
6830 				       struct net_device *dev,
6831 				       struct hdd_station_info *stainfo,
6832 				       struct station_info *sinfo)
6833 {
6834 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
6835 	struct hdd_context *hddctx = wiphy_priv(wiphy);
6836 	struct stats_event *stats;
6837 	struct hdd_fw_txrx_stats txrx_stats;
6838 	int i, status;
6839 
6840 	stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(adapter->deflink->vdev,
6841 							 stainfo->sta_mac.bytes,
6842 							 &status);
6843 	if (status || !stats) {
6844 		wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
6845 		hdd_err("fail to get peer info from fw");
6846 		return -EPERM;
6847 	}
6848 
6849 	for (i = 0; i < WMI_MAX_CHAINS; i++)
6850 		stainfo->peer_rssi_per_chain[i] =
6851 			    stats->peer_stats_info_ext->peer_rssi_per_chain[i];
6852 
6853 	qdf_mem_zero(&txrx_stats, sizeof(txrx_stats));
6854 	txrx_stats.tx_packets = stats->peer_stats_info_ext->tx_packets;
6855 	txrx_stats.tx_bytes = stats->peer_stats_info_ext->tx_bytes;
6856 	txrx_stats.rx_packets = stats->peer_stats_info_ext->rx_packets;
6857 	txrx_stats.rx_bytes = stats->peer_stats_info_ext->rx_bytes;
6858 	txrx_stats.tx_retries = stats->peer_stats_info_ext->tx_retries;
6859 	txrx_stats.tx_failed = stats->peer_stats_info_ext->tx_failed;
6860 	txrx_stats.tx_succeed = stats->peer_stats_info_ext->tx_succeed;
6861 	txrx_stats.rssi = stats->peer_stats_info_ext->rssi;
6862 	wlan_hdd_fill_rate_info(&txrx_stats, stats->peer_stats_info_ext);
6863 	wlan_hdd_fill_station_info(hddctx->psoc, adapter,
6864 				   sinfo, stainfo, &txrx_stats);
6865 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
6866 
6867 	return status;
6868 }
6869 
6870 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \
6871 	defined(WLAN_FEATURE_11AX)
6872 /**
6873  * hdd_map_he_gi_to_os() - map txrate_gi to os guard interval
6874  * @guard_interval: guard interval get from fw rate
6875  *
6876  * Return: os guard interval value
6877  */
hdd_map_he_gi_to_os(enum txrate_gi guard_interval)6878 static inline uint8_t hdd_map_he_gi_to_os(enum txrate_gi guard_interval)
6879 {
6880 	switch (guard_interval) {
6881 	case TXRATE_GI_0_8_US:
6882 		return NL80211_RATE_INFO_HE_GI_0_8;
6883 	case TXRATE_GI_1_6_US:
6884 		return NL80211_RATE_INFO_HE_GI_1_6;
6885 	case TXRATE_GI_3_2_US:
6886 		return NL80211_RATE_INFO_HE_GI_3_2;
6887 	default:
6888 		return NL80211_RATE_INFO_HE_GI_0_8;
6889 	}
6890 }
6891 
6892 /**
6893  * wlan_hdd_fill_os_he_rateflags() - Fill HE related rate_info
6894  * @os_rate: rate info for os
6895  * @rate_flags: rate flags
6896  * @dcm: dcm from rate
6897  * @guard_interval: guard interval from rate
6898  *
6899  * Return: none
6900  */
wlan_hdd_fill_os_he_rateflags(struct rate_info * os_rate,enum tx_rate_info rate_flags,uint8_t dcm,enum txrate_gi guard_interval)6901 static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
6902 					  enum tx_rate_info rate_flags,
6903 					  uint8_t dcm,
6904 					  enum txrate_gi guard_interval)
6905 {
6906 	/* as fw not yet report ofdma to host, so we doesn't
6907 	 * fill RATE_INFO_BW_HE_RU.
6908 	 */
6909 	if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
6910 		TX_RATE_HE20 | TX_RATE_HE160)) {
6911 		if (rate_flags & TX_RATE_HE160)
6912 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_160);
6913 		else if (rate_flags & TX_RATE_HE80)
6914 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
6915 		else if (rate_flags & TX_RATE_HE40)
6916 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
6917 
6918 		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
6919 
6920 		os_rate->he_gi = hdd_map_he_gi_to_os(guard_interval);
6921 		os_rate->he_dcm = dcm;
6922 	}
6923 }
6924 #else
wlan_hdd_fill_os_he_rateflags(struct rate_info * os_rate,enum tx_rate_info rate_flags,uint8_t dcm,enum txrate_gi guard_interval)6925 static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
6926 					  enum tx_rate_info rate_flags,
6927 					  uint8_t dcm,
6928 					  enum txrate_gi guard_interval)
6929 {}
6930 #endif
6931 
6932 /**
6933  * wlan_hdd_fill_os_rate_info() - Fill os related rate_info
6934  * @rate_flags: rate flags
6935  * @legacy_rate: 802.11abg rate
6936  * @os_rate: rate info for os
6937  * @mcs_index: mcs
6938  * @nss: number of spatial streams
6939  * @dcm: dcm from rate
6940  * @guard_interval: guard interval from rate
6941  *
6942  * Return: none
6943  */
wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,uint16_t legacy_rate,struct rate_info * os_rate,uint8_t mcs_index,uint8_t nss,uint8_t dcm,enum txrate_gi guard_interval)6944 static void wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,
6945 				       uint16_t legacy_rate,
6946 				       struct rate_info *os_rate,
6947 				       uint8_t mcs_index, uint8_t nss,
6948 				       uint8_t dcm,
6949 				       enum txrate_gi guard_interval)
6950 {
6951 	os_rate->nss = nss;
6952 	if (rate_flags & TX_RATE_LEGACY) {
6953 		os_rate->legacy = legacy_rate;
6954 		hdd_debug("Reporting legacy rate %d", os_rate->legacy);
6955 		return;
6956 	}
6957 
6958 	/* assume basic BW. anything else will override this later */
6959 	hdd_set_rate_bw(os_rate, HDD_RATE_BW_20);
6960 	os_rate->mcs = mcs_index;
6961 
6962 	wlan_hdd_fill_os_eht_rateflags(os_rate, rate_flags, dcm,
6963 				       guard_interval);
6964 	wlan_hdd_fill_os_he_rateflags(os_rate, rate_flags, dcm, guard_interval);
6965 
6966 	if (rate_flags & (TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 |
6967 	    TX_RATE_VHT20)) {
6968 		if (rate_flags & TX_RATE_VHT160)
6969 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_160);
6970 		else if (rate_flags & TX_RATE_VHT80)
6971 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
6972 		else if (rate_flags & TX_RATE_VHT40)
6973 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
6974 		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
6975 	}
6976 
6977 	if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
6978 		if (rate_flags & TX_RATE_HT40)
6979 			hdd_set_rate_bw(os_rate,
6980 					HDD_RATE_BW_40);
6981 		os_rate->flags |= RATE_INFO_FLAGS_MCS;
6982 	}
6983 
6984 	if (rate_flags & TX_RATE_SGI)
6985 		os_rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
6986 }
6987 
hdd_get_max_tx_bitrate(struct wlan_hdd_link_info * link_info)6988 void hdd_get_max_tx_bitrate(struct wlan_hdd_link_info *link_info)
6989 {
6990 	struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx;
6991 	struct station_info sinfo;
6992 	enum tx_rate_info tx_rate_flags;
6993 	uint8_t tx_mcs_index, tx_nss = 1;
6994 	uint16_t my_tx_rate;
6995 	struct hdd_station_ctx *hdd_sta_ctx;
6996 	struct wlan_objmgr_vdev *vdev;
6997 
6998 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
6999 
7000 	qdf_mem_zero(&sinfo, sizeof(struct station_info));
7001 
7002 	sinfo.signal = link_info->rssi;
7003 	tx_mcs_index = link_info->hdd_stats.class_a_stat.tx_mcs_index;
7004 	my_tx_rate = link_info->hdd_stats.class_a_stat.tx_rate;
7005 	tx_rate_flags = link_info->hdd_stats.class_a_stat.tx_rx_rate_flags;
7006 
7007 	if (!(tx_rate_flags & TX_RATE_LEGACY)) {
7008 		vdev = hdd_objmgr_get_vdev_by_user(link_info,
7009 						   WLAN_OSIF_STATS_ID);
7010 		if (vdev) {
7011 			/*
7012 			 * Take static NSS for reporting max rates.
7013 			 * NSS from FW is not reliable as it changes
7014 			 * as per the environment quality.
7015 			 */
7016 			tx_nss = wlan_vdev_mlme_get_nss(vdev);
7017 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7018 		} else {
7019 			tx_nss = link_info->hdd_stats.class_a_stat.tx_nss;
7020 		}
7021 		hdd_check_and_update_nss(hdd_ctx, &tx_nss, NULL);
7022 
7023 		if (tx_mcs_index == INVALID_MCS_IDX)
7024 			tx_mcs_index = 0;
7025 	}
7026 
7027 	if (hdd_report_max_rate(link_info, hdd_ctx->mac_handle, &sinfo.txrate,
7028 				sinfo.signal, tx_rate_flags, tx_mcs_index,
7029 				my_tx_rate, tx_nss)) {
7030 		hdd_sta_ctx->cache_conn_info.max_tx_bitrate = sinfo.txrate;
7031 		hdd_debug("Reporting max tx rate flags %d mcs %d nss %d bw %d",
7032 			  sinfo.txrate.flags, sinfo.txrate.mcs,
7033 			  sinfo.txrate.nss, sinfo.txrate.bw);
7034 	}
7035 }
7036 
hdd_report_max_rate(struct wlan_hdd_link_info * link_info,mac_handle_t mac_handle,struct rate_info * rate,int8_t signal,enum tx_rate_info rate_flags,uint8_t mcs_index,uint16_t fw_rate,uint8_t nss)7037 bool hdd_report_max_rate(struct wlan_hdd_link_info *link_info,
7038 			 mac_handle_t mac_handle,
7039 			 struct rate_info *rate,
7040 			 int8_t signal,
7041 			 enum tx_rate_info rate_flags,
7042 			 uint8_t mcs_index,
7043 			 uint16_t fw_rate, uint8_t nss)
7044 {
7045 	uint8_t i, j, rssidx = 0;
7046 	uint16_t max_rate = 0;
7047 	uint32_t vht_mcs_map;
7048 	bool is_vht20_mcs9 = false;
7049 	uint16_t he_mcs_12_13_map = 0;
7050 	uint16_t current_rate = 0;
7051 	qdf_size_t or_leng;
7052 	uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX];
7053 	uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
7054 	qdf_size_t er_leng;
7055 	uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET];
7056 	qdf_size_t mcs_len;
7057 	struct index_data_rate_type *supported_mcs_rate;
7058 	enum data_rate_11ac_max_mcs vht_max_mcs;
7059 	uint8_t max_mcs_idx = 0;
7060 	uint8_t max_ht_mcs_idx;
7061 	uint8_t rate_flag = 1;
7062 	int mode = 0, max_ht_idx;
7063 	QDF_STATUS stat = QDF_STATUS_E_FAILURE;
7064 	struct hdd_context *hdd_ctx;
7065 	int link_speed_rssi_high = 0;
7066 	int link_speed_rssi_mid = 0;
7067 	int link_speed_rssi_low = 0;
7068 	uint32_t link_speed_rssi_report = 0;
7069 	struct wlan_objmgr_vdev *vdev;
7070 
7071 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
7072 	if (!hdd_ctx)
7073 		return false;
7074 
7075 	ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
7076 				       &link_speed_rssi_high,
7077 				       &link_speed_rssi_mid,
7078 				       &link_speed_rssi_low,
7079 				       &link_speed_rssi_report);
7080 
7081 	if (ucfg_mlme_stats_is_link_speed_report_max_scaled(hdd_ctx->psoc)) {
7082 		/* report the max possible speed with RSSI scaling */
7083 		if (signal >= link_speed_rssi_high) {
7084 			/* report the max possible speed */
7085 			rssidx = 0;
7086 		} else if (signal >= link_speed_rssi_mid) {
7087 			/* report middle speed */
7088 			rssidx = 1;
7089 		} else if (signal >= link_speed_rssi_low) {
7090 			/* report middle speed */
7091 			rssidx = 2;
7092 		} else {
7093 			/* report actual speed */
7094 			rssidx = 3;
7095 		}
7096 	}
7097 
7098 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
7099 	if (!vdev) {
7100 		hdd_err("failed to get vdev");
7101 		return false;
7102 	}
7103 
7104 	/* Get Basic Rate Set */
7105 	or_leng = ucfg_mlme_get_opr_rate(vdev, operational_rates,
7106 					 sizeof(operational_rates));
7107 	for (i = 0; i < or_leng; i++) {
7108 		for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
7109 			/* Validate Rate Set */
7110 			if (supported_data_rate[j].beacon_rate_index ==
7111 				(operational_rates[i] & 0x7F)) {
7112 				current_rate =
7113 					supported_data_rate[j].
7114 					supported_rate[rssidx];
7115 				break;
7116 			}
7117 		}
7118 		/* Update MAX rate */
7119 		max_rate = (current_rate > max_rate) ? current_rate : max_rate;
7120 	}
7121 
7122 	/* Get Extended Rate Set */
7123 	er_leng = ucfg_mlme_get_ext_opr_rate(vdev, extended_rates,
7124 					     sizeof(extended_rates));
7125 	he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev);
7126 
7127 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7128 	for (i = 0; i < er_leng; i++) {
7129 		for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
7130 			if (supported_data_rate[j].beacon_rate_index ==
7131 			    (extended_rates[i] & 0x7F)) {
7132 				current_rate = supported_data_rate[j].
7133 					       supported_rate[rssidx];
7134 				break;
7135 			}
7136 		}
7137 		/* Update MAX rate */
7138 		max_rate = (current_rate > max_rate) ? current_rate : max_rate;
7139 	}
7140 	/* Get MCS Rate Set --
7141 	 * Only if we are connected in non legacy mode and not reporting
7142 	 * actual speed
7143 	 */
7144 	if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
7145 		rate_flag = 0;
7146 		if (rate_flags & (TX_RATE_VHT80 | TX_RATE_HE80 |
7147 				TX_RATE_HE160 | TX_RATE_VHT160 |
7148 				TX_RATE_EHT80 | TX_RATE_EHT160 |
7149 				TX_RATE_EHT320))
7150 			mode = 2;
7151 		else if (rate_flags & (TX_RATE_HT40 |
7152 			 TX_RATE_VHT40 | TX_RATE_HE40 | TX_RATE_EHT40))
7153 			mode = 1;
7154 		else
7155 			mode = 0;
7156 
7157 		if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
7158 		    TX_RATE_VHT80 | TX_RATE_HE20 | TX_RATE_HE40 |
7159 		    TX_RATE_HE80 | TX_RATE_HE160 | TX_RATE_VHT160 |
7160 		    TX_RATE_EHT20 | TX_RATE_EHT40 | TX_RATE_EHT80 |
7161 		    TX_RATE_EHT160 | TX_RATE_EHT320)) {
7162 			stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc,
7163 								&vht_mcs_map);
7164 			if (QDF_IS_STATUS_ERROR(stat))
7165 				hdd_err("failed to get tx_mcs_map");
7166 
7167 			stat = ucfg_mlme_get_vht20_mcs9(hdd_ctx->psoc,
7168 							&is_vht20_mcs9);
7169 			if (QDF_IS_STATUS_ERROR(stat))
7170 				hdd_err("Failed to get VHT20 MCS9 enable val");
7171 
7172 			vht_max_mcs = (enum data_rate_11ac_max_mcs)
7173 				(vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
7174 			if (rate_flags & TX_RATE_SGI)
7175 				rate_flag |= 1;
7176 
7177 			if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs) {
7178 				max_mcs_idx = 7;
7179 			} else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs) {
7180 				max_mcs_idx = 8;
7181 			} else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs) {
7182 				/*
7183 				 * If the ini enable_vht20_mcs9 is disabled,
7184 				 * then max mcs index should not be set to 9
7185 				 * for TX_RATE_VHT20
7186 				 */
7187 				if (!is_vht20_mcs9 &&
7188 				    (rate_flags & TX_RATE_VHT20))
7189 					max_mcs_idx = 8;
7190 				else
7191 					max_mcs_idx = 9;
7192 			}
7193 
7194 			if (rate_flags & (TX_RATE_EHT20 | TX_RATE_EHT40 |
7195 			    TX_RATE_EHT80 | TX_RATE_EHT160 | TX_RATE_EHT320))
7196 				max_mcs_idx = 13;
7197 
7198 			if (rate_flags & (TX_RATE_HE20 | TX_RATE_HE40 |
7199 			    TX_RATE_HE80 | TX_RATE_HE160)) {
7200 				max_mcs_idx = 11;
7201 				if (he_mcs_12_13_map)
7202 					max_mcs_idx = 13;
7203 			}
7204 
7205 			if (rssidx != 0) {
7206 				for (i = 0; i <= max_mcs_idx; i++) {
7207 					if (signal <= rssi_mcs_tbl[mode][i]) {
7208 						max_mcs_idx = i;
7209 						break;
7210 					}
7211 				}
7212 			}
7213 
7214 			max_mcs_idx = (max_mcs_idx > mcs_index) ?
7215 				max_mcs_idx : mcs_index;
7216 		} else {
7217 			mcs_len = ucfg_mlme_get_mcs_rate(link_info->vdev,
7218 							 mcs_rates,
7219 							 sizeof(mcs_rates));
7220 			if (!mcs_len) {
7221 				hdd_err("Failed to get current mcs rate set");
7222 				/*To keep GUI happy */
7223 				return false;
7224 			}
7225 
7226 			if (rate_flags & TX_RATE_HT40)
7227 				rate_flag |= 1;
7228 			if (rate_flags & TX_RATE_SGI)
7229 				rate_flag |= 2;
7230 
7231 			supported_mcs_rate =
7232 				(struct index_data_rate_type *)
7233 				((nss == 1) ? &supported_mcs_rate_nss1 :
7234 				 &supported_mcs_rate_nss2);
7235 			max_ht_mcs_idx =
7236 				QDF_ARRAY_SIZE(supported_mcs_rate_nss1);
7237 			max_ht_idx = max_ht_mcs_idx;
7238 			if (rssidx != 0) {
7239 				for (i = 0; i < max_ht_mcs_idx; i++) {
7240 					if (signal <= rssi_mcs_tbl[mode][i]) {
7241 						max_ht_idx = i + 1;
7242 						break;
7243 					}
7244 				}
7245 			}
7246 
7247 			for (i = 0; i < mcs_len; i++) {
7248 				for (j = 0; j < max_ht_idx; j++) {
7249 					if (supported_mcs_rate[j].
7250 						beacon_rate_index ==
7251 						mcs_rates[i]) {
7252 						current_rate =
7253 						  supported_mcs_rate[j].
7254 						  supported_rate
7255 						  [rate_flag];
7256 						max_mcs_idx =
7257 						  supported_mcs_rate[j].
7258 						  beacon_rate_index;
7259 						break;
7260 					}
7261 				}
7262 
7263 				if ((j < max_ht_mcs_idx) &&
7264 				    (current_rate > max_rate))
7265 					max_rate = current_rate;
7266 			}
7267 
7268 			if (nss == 2)
7269 				max_mcs_idx += max_ht_mcs_idx;
7270 			max_mcs_idx = (max_mcs_idx > mcs_index) ?
7271 				max_mcs_idx : mcs_index;
7272 		}
7273 	}
7274 
7275 	else if (!(rate_flags & TX_RATE_LEGACY)) {
7276 		max_rate = fw_rate;
7277 		max_mcs_idx = mcs_index;
7278 	}
7279 	/* report a value at least as big as current rate */
7280 	if ((max_rate < fw_rate) || (0 == max_rate)) {
7281 		max_rate = fw_rate;
7282 	}
7283 	hdd_debug("RLMS %u, rate_flags 0x%x, max_rate %d mcs %d nss %d",
7284 		  link_speed_rssi_report, rate_flags,
7285 		  max_rate, max_mcs_idx, nss);
7286 	wlan_hdd_fill_os_rate_info(rate_flags, max_rate, rate,
7287 				   max_mcs_idx, nss, 0, 0);
7288 
7289 	return true;
7290 }
7291 
7292 /**
7293  * hdd_report_actual_rate() - Fill the actual rate stats.
7294  * @rate_flags: The rate flags computed from rate
7295  * @my_rate: The rate from fw stats
7296  * @rate: The station_info struct member struct rate_info to be filled
7297  * @mcs_index: The mcs index computed from rate
7298  * @nss: The NSS from fw stats
7299  * @dcm: the dcm computed from rate
7300  * @guard_interval: the guard interval computed from rate
7301  *
7302  * Return: None
7303  */
hdd_report_actual_rate(enum tx_rate_info rate_flags,uint16_t my_rate,struct rate_info * rate,uint8_t mcs_index,uint8_t nss,uint8_t dcm,enum txrate_gi guard_interval)7304 static void hdd_report_actual_rate(enum tx_rate_info rate_flags,
7305 				   uint16_t my_rate,
7306 				   struct rate_info *rate, uint8_t mcs_index,
7307 				   uint8_t nss, uint8_t dcm,
7308 				   enum txrate_gi guard_interval)
7309 {
7310 	/* report current rate instead of max rate */
7311 	wlan_hdd_fill_os_rate_info(rate_flags, my_rate, rate,
7312 				   mcs_index, nss, dcm, guard_interval);
7313 }
7314 
7315 /**
7316  * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats
7317  *
7318  * @sinfo: The station_info structure to be filled.
7319  * @link_info: pointer to link_info struct in adapter
7320  *
7321  * Return: None
7322  */
7323 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
7324 static void
hdd_wlan_fill_per_chain_rssi_stats(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7325 hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
7326 				   struct wlan_hdd_link_info *link_info)
7327 {
7328 	bool rssi_stats_valid = false;
7329 	uint8_t i;
7330 
7331 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
7332 	for (i = 0; i < NUM_CHAINS_MAX; i++) {
7333 		sinfo->chain_signal_avg[i] =
7334 			   link_info->hdd_stats.per_chain_rssi_stats.rssi[i];
7335 		sinfo->chains |= 1 << i;
7336 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
7337 		    sinfo->chain_signal_avg[i] != 0)
7338 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
7339 
7340 		hdd_debug("RSSI for chain %d, vdev_id %d is %d",
7341 			  i, link_info->vdev_id, sinfo->chain_signal_avg[i]);
7342 
7343 		if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
7344 			rssi_stats_valid = true;
7345 	}
7346 
7347 	if (rssi_stats_valid) {
7348 		sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
7349 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
7350 	}
7351 }
7352 #else
7353 static inline void
hdd_wlan_fill_per_chain_rssi_stats(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7354 hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
7355 				   struct wlan_hdd_link_info *link_info)
7356 {
7357 }
7358 #endif
7359 
7360 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || \
7361 	defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT)
hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7362 static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info,
7363 					struct station_info *sinfo)
7364 {
7365 	sinfo->rx_mpdu_count = link_info->hdd_stats.peer_stats.rx_count;
7366 	sinfo->fcs_err_count = link_info->hdd_stats.peer_stats.fcs_count;
7367 	hdd_debug("RX mpdu count %d fcs_err_count %d",
7368 		  sinfo->rx_mpdu_count, sinfo->fcs_err_count);
7369 	sinfo->filled |= HDD_INFO_FCS_ERROR_COUNT | HDD_INFO_RX_MPDUS;
7370 }
7371 #else
hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7372 static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info,
7373 					struct station_info *sinfo)
7374 {
7375 }
7376 #endif
7377 
hdd_check_and_update_nss(struct hdd_context * hdd_ctx,uint8_t * tx_nss,uint8_t * rx_nss)7378 void hdd_check_and_update_nss(struct hdd_context *hdd_ctx,
7379 			      uint8_t *tx_nss, uint8_t *rx_nss)
7380 {
7381 	if (tx_nss && (*tx_nss > 1) &&
7382 	    policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
7383 	    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
7384 		hdd_debug("Hw mode is DBS, Reduce tx nss(%d) to 1", *tx_nss);
7385 		(*tx_nss)--;
7386 	}
7387 
7388 	if (rx_nss && (*rx_nss > 1) &&
7389 	    policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
7390 	    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
7391 		hdd_debug("Hw mode is DBS, Reduce rx nss(%d) to 1", *rx_nss);
7392 		(*rx_nss)--;
7393 	}
7394 }
7395 
7396 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
7397 static void
wlan_hdd_refill_os_bw(struct rate_info * os_rate,enum rx_tlv_bw bw)7398 wlan_hdd_refill_os_bw(struct rate_info *os_rate, enum rx_tlv_bw bw)
7399 {
7400 	if (bw == RX_TLV_BW_20MHZ)
7401 		os_rate->bw = RATE_INFO_BW_20;
7402 	else if (bw == RX_TLV_BW_40MHZ)
7403 		os_rate->bw = RATE_INFO_BW_40;
7404 	else if (bw == RX_TLV_BW_80MHZ)
7405 		os_rate->bw = RATE_INFO_BW_80;
7406 	else if (bw == RX_TLV_BW_160MHZ)
7407 		os_rate->bw = RATE_INFO_BW_160;
7408 	else
7409 		wlan_hdd_refill_os_eht_bw(os_rate, bw);
7410 }
7411 
7412 static void
wlan_hdd_refill_os_rateflags(struct rate_info * os_rate,uint8_t preamble)7413 wlan_hdd_refill_os_rateflags(struct rate_info *os_rate, uint8_t preamble)
7414 {
7415 	if (preamble == DOT11_N)
7416 		os_rate->flags |= RATE_INFO_FLAGS_MCS;
7417 	else if (preamble == DOT11_AC)
7418 		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
7419 	else if (preamble == DOT11_AX)
7420 		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
7421 	else
7422 		wlan_hdd_refill_os_eht_rateflags(os_rate, preamble);
7423 }
7424 
7425 /**
7426  * wlan_hdd_refill_actual_rate() - Refill actual rates info stats
7427  * @sinfo: kernel station_info struct to populate
7428  * @link_info: pointer to link_info struct in adapter,
7429  *             where hdd_stats is located in this struct
7430  *
7431  * This function is to replace RX rates which was previously filled by fw.
7432  *
7433  * Return: None
7434  */
7435 static void
wlan_hdd_refill_actual_rate(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7436 wlan_hdd_refill_actual_rate(struct station_info *sinfo,
7437 			    struct wlan_hdd_link_info *link_info)
7438 {
7439 	uint8_t preamble = link_info->hdd_stats.class_a_stat.rx_preamble;
7440 
7441 	sinfo->rxrate.nss = link_info->hdd_stats.class_a_stat.rx_nss;
7442 	if (preamble == DOT11_A || preamble == DOT11_B) {
7443 		/* Clear rxrate which may have been set previously */
7444 		qdf_mem_zero(&sinfo->rxrate, sizeof(sinfo->rxrate));
7445 		sinfo->rxrate.legacy =
7446 			link_info->hdd_stats.class_a_stat.rx_rate;
7447 		hdd_debug("Reporting legacy rate %d", sinfo->rxrate.legacy);
7448 		return;
7449 	} else if (qdf_unlikely(preamble == INVALID_PREAMBLE)) {
7450 		/*
7451 		 * If preamble is invalid, it means that DP has not received
7452 		 * a data frame since assoc or roaming so there is no rates.
7453 		 * In this case, using FW rates which was set previously.
7454 		 */
7455 		hdd_debug("Driver failed to get rate, reporting FW rate");
7456 		return;
7457 	}
7458 
7459 	wlan_hdd_refill_os_rateflags(&sinfo->rxrate, preamble);
7460 
7461 	sinfo->rxrate.mcs = link_info->hdd_stats.class_a_stat.rx_mcs_index;
7462 
7463 	wlan_hdd_refill_os_bw(&sinfo->rxrate,
7464 			      link_info->hdd_stats.class_a_stat.rx_bw);
7465 	/* Fill out gi and dcm in HE mode */
7466 	sinfo->rxrate.he_gi =
7467 		hdd_map_he_gi_to_os(link_info->hdd_stats.class_a_stat.rx_gi);
7468 	sinfo->rxrate.he_dcm = 0;
7469 
7470 	if (link_info->hdd_stats.class_a_stat.rx_gi == TXRATE_GI_0_4_US)
7471 		sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
7472 
7473 	hdd_debug("sgi=%d, preamble=%d, bw=%d, mcs=%d, nss=%d, rate_flag=0x%x",
7474 		  link_info->hdd_stats.class_a_stat.rx_gi, preamble,
7475 		  link_info->hdd_stats.class_a_stat.rx_bw,
7476 		  link_info->hdd_stats.class_a_stat.rx_mcs_index,
7477 		  link_info->hdd_stats.class_a_stat.rx_nss,
7478 		  sinfo->rxrate.flags);
7479 }
7480 #else
7481 static inline void
wlan_hdd_refill_actual_rate(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7482 wlan_hdd_refill_actual_rate(struct station_info *sinfo,
7483 			    struct wlan_hdd_link_info *link_info)
7484 {
7485 }
7486 #endif
7487 
wlan_hdd_update_rssi(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7488 static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info,
7489 				 struct station_info *sinfo)
7490 {
7491 	struct hdd_station_ctx *sta_ctx;
7492 	int8_t snr;
7493 	mac_handle_t mac_handle;
7494 
7495 	mac_handle = hdd_adapter_get_mac_handle(link_info->adapter);
7496 	if (!mac_handle) {
7497 		hdd_err("mac ctx NULL");
7498 		return;
7499 	}
7500 
7501 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7502 	link_info->rssi = link_info->hdd_stats.summary_stat.rssi;
7503 	link_info->snr = link_info->hdd_stats.summary_stat.snr;
7504 	snr = link_info->snr;
7505 
7506 	/* for new connection there might be no valid previous RSSI */
7507 	if (!link_info->rssi) {
7508 		hdd_get_rssi_snr_by_bssid(mac_handle,
7509 					  sta_ctx->conn_info.bssid.bytes,
7510 					  &link_info->rssi, &snr);
7511 	}
7512 
7513 	/* If RSSi is reported as positive then it is invalid */
7514 	if (link_info->rssi >= 0) {
7515 		hdd_debug_rl("Invalid RSSI %d, reset to -1", link_info->rssi);
7516 		link_info->rssi = -1;
7517 		link_info->hdd_stats.summary_stat.rssi = -1;
7518 	}
7519 
7520 	sinfo->signal = link_info->rssi;
7521 	hdd_debug("snr: %d, rssi: %d",
7522 		  link_info->hdd_stats.summary_stat.snr,
7523 		  link_info->hdd_stats.summary_stat.rssi);
7524 	sta_ctx->conn_info.signal = sinfo->signal;
7525 	sta_ctx->conn_info.noise = sta_ctx->conn_info.signal - snr;
7526 	sta_ctx->cache_conn_info.signal = sinfo->signal;
7527 	sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise;
7528 	sinfo->filled |= HDD_INFO_SIGNAL;
7529 }
7530 
7531 static void
wlan_hdd_update_mlo_peer_stats(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7532 wlan_hdd_update_mlo_peer_stats(struct wlan_hdd_link_info *link_info,
7533 			       struct station_info *sinfo)
7534 {
7535 	ol_txrx_soc_handle soc;
7536 	uint8_t *peer_mac;
7537 	struct cdp_peer_stats *peer_stats;
7538 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
7539 
7540 	if (wlan_hdd_validate_context(hdd_ctx)) {
7541 		hdd_err("invalid hdd_ctx");
7542 		return;
7543 	}
7544 
7545 	soc = cds_get_context(QDF_MODULE_ID_SOC);
7546 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
7547 
7548 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
7549 		return;
7550 
7551 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
7552 	if (!peer_stats) {
7553 		hdd_err("Failed to allocated memory for peer_stats");
7554 		return;
7555 	}
7556 
7557 	ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
7558 					peer_mac, peer_stats,
7559 					CDP_WILD_PEER_TYPE,
7560 					WLAN_MAX_MLD);
7561 
7562 	sinfo->tx_bytes = peer_stats->tx.tx_success.bytes;
7563 	sinfo->rx_bytes = peer_stats->rx.rcvd.bytes;
7564 	sinfo->rx_packets = peer_stats->rx.rcvd.num;
7565 
7566 	hdd_nofl_debug("Updated sinfo with per peer stats");
7567 	qdf_mem_free(peer_stats);
7568 }
7569 
wlan_hdd_update_rate_info(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7570 static int wlan_hdd_update_rate_info(struct wlan_hdd_link_info *link_info,
7571 				     struct station_info *sinfo)
7572 {
7573 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
7574 	struct hdd_station_ctx *sta_ctx;
7575 	mac_handle_t mac_handle;
7576 	struct wlan_objmgr_vdev *vdev;
7577 	enum tx_rate_info rate_flags, tx_rate_flags, rx_rate_flags;
7578 	enum txrate_gi tx_gi, rx_gi;
7579 	uint32_t link_speed_rssi_report = 0;
7580 	int link_speed_rssi_high = 0;
7581 	int link_speed_rssi_mid = 0;
7582 	int link_speed_rssi_low = 0;
7583 	uint16_t my_tx_rate, my_rx_rate;
7584 	uint8_t tx_mcs_index, rx_mcs_index;
7585 	uint8_t tx_nss = 1, rx_nss = 1, tx_dcm, rx_dcm;
7586 	qdf_net_dev_stats stats = {0};
7587 	struct hdd_stats *hdd_stats;
7588 
7589 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7590 	ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
7591 				       &link_speed_rssi_high,
7592 				       &link_speed_rssi_mid,
7593 				       &link_speed_rssi_low,
7594 				       &link_speed_rssi_report);
7595 
7596 	hdd_stats = &link_info->hdd_stats;
7597 	rate_flags = hdd_stats->class_a_stat.tx_rx_rate_flags;
7598 	tx_rate_flags = rx_rate_flags = rate_flags;
7599 
7600 	tx_mcs_index = hdd_stats->class_a_stat.tx_mcs_index;
7601 	rx_mcs_index = hdd_stats->class_a_stat.rx_mcs_index;
7602 	mac_handle = hdd_ctx->mac_handle;
7603 
7604 	/* convert to the UI units of 100kbps */
7605 	my_tx_rate = hdd_stats->class_a_stat.tx_rate;
7606 	my_rx_rate = hdd_stats->class_a_stat.rx_rate;
7607 
7608 	tx_dcm = hdd_stats->class_a_stat.tx_dcm;
7609 	rx_dcm = hdd_stats->class_a_stat.rx_dcm;
7610 	tx_gi = hdd_stats->class_a_stat.tx_gi;
7611 	rx_gi = hdd_stats->class_a_stat.rx_gi;
7612 
7613 	if (!(rate_flags & TX_RATE_LEGACY)) {
7614 		tx_nss = hdd_stats->class_a_stat.tx_nss;
7615 		rx_nss = hdd_stats->class_a_stat.rx_nss;
7616 
7617 		hdd_check_and_update_nss(hdd_ctx, &tx_nss, &rx_nss);
7618 
7619 		if (ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
7620 			/* Get current rate flags if report actual */
7621 			/* WMA fails to find mcs_index for legacy tx rates */
7622 			if (tx_mcs_index == INVALID_MCS_IDX && my_tx_rate)
7623 				tx_rate_flags = TX_RATE_LEGACY;
7624 			else
7625 				tx_rate_flags =
7626 				    hdd_stats->class_a_stat.tx_mcs_rate_flags;
7627 
7628 			if (rx_mcs_index == INVALID_MCS_IDX && my_rx_rate)
7629 				rx_rate_flags = TX_RATE_LEGACY;
7630 			else
7631 				rx_rate_flags =
7632 				    hdd_stats->class_a_stat.rx_mcs_rate_flags;
7633 		}
7634 
7635 		if (tx_mcs_index == INVALID_MCS_IDX)
7636 			tx_mcs_index = 0;
7637 		if (rx_mcs_index == INVALID_MCS_IDX)
7638 			rx_mcs_index = 0;
7639 	}
7640 
7641 	hdd_debug("[RSSI %d, RLMS %u, rssi high %d, rssi mid %d, rssi low %d]-"
7642 		  "[Rate info: TX: %d, RX: %d]-[Rate flags: TX: 0x%x, RX: 0x%x]"
7643 		  "-[MCS Index: TX: %d, RX: %d]-[NSS: TX: %d, RX: %d]-"
7644 		  "[dcm: TX: %d, RX: %d]-[guard interval: TX: %d, RX: %d",
7645 		  sinfo->signal, link_speed_rssi_report,
7646 		  link_speed_rssi_high, link_speed_rssi_mid,
7647 		  link_speed_rssi_low, my_tx_rate, my_rx_rate,
7648 		  (int)tx_rate_flags, (int)rx_rate_flags, (int)tx_mcs_index,
7649 		  (int)rx_mcs_index, (int)tx_nss, (int)rx_nss,
7650 		  (int)tx_dcm, (int)rx_dcm, (int)tx_gi, (int)rx_gi);
7651 
7652 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
7653 
7654 	if (!vdev) {
7655 		hdd_nofl_debug("vdev object NULL");
7656 		return -EINVAL;
7657 	}
7658 
7659 	if (sinfo->signal == WLAN_INVALID_RSSI_VALUE) {
7660 		hdd_debug("don't fill tx rx rate for inactive link");
7661 	} else if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
7662 		bool tx_rate_calc, rx_rate_calc;
7663 		uint8_t tx_nss_max, rx_nss_max;
7664 
7665 		/*
7666 		 * Take static NSS for reporting max rates. NSS from the FW
7667 		 * is not reliable as it changes as per the environment
7668 		 * quality.
7669 		 */
7670 		tx_nss_max = wlan_vdev_mlme_get_nss(vdev);
7671 		rx_nss_max = wlan_vdev_mlme_get_nss(vdev);
7672 
7673 		hdd_check_and_update_nss(hdd_ctx, &tx_nss_max, &rx_nss_max);
7674 
7675 		tx_rate_calc = hdd_report_max_rate(link_info, mac_handle,
7676 						   &sinfo->txrate,
7677 						   sinfo->signal,
7678 						   tx_rate_flags,
7679 						   tx_mcs_index,
7680 						   my_tx_rate,
7681 						   tx_nss_max);
7682 
7683 		rx_rate_calc = hdd_report_max_rate(link_info, mac_handle,
7684 						   &sinfo->rxrate,
7685 						   sinfo->signal,
7686 						   rx_rate_flags,
7687 						   rx_mcs_index,
7688 						   my_rx_rate,
7689 						   rx_nss_max);
7690 
7691 		if (!tx_rate_calc || !rx_rate_calc) {
7692 			hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
7693 					       &sinfo->txrate, tx_mcs_index,
7694 					       tx_nss, tx_dcm, tx_gi);
7695 
7696 			hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
7697 					       &sinfo->rxrate, rx_mcs_index,
7698 					       rx_nss, rx_dcm, rx_gi);
7699 		}
7700 	} else {
7701 		/* Fill TX stats */
7702 		hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
7703 				       &sinfo->txrate, tx_mcs_index,
7704 				       tx_nss, tx_dcm, tx_gi);
7705 
7706 		/* Fill RX stats */
7707 		hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
7708 				       &sinfo->rxrate, rx_mcs_index,
7709 				       rx_nss, rx_dcm, rx_gi);
7710 
7711 		/* Using driver RX rate to replace the FW RX rate */
7712 		wlan_hdd_refill_actual_rate(sinfo, link_info);
7713 	}
7714 
7715 	wlan_hdd_fill_summary_stats(&hdd_stats->summary_stat,
7716 				    sinfo, link_info->vdev_id);
7717 
7718 	wlan_hdd_fill_per_link_summary_stats(&hdd_stats->summary_stat,
7719 					     sinfo, link_info);
7720 
7721 	ucfg_dp_get_net_dev_stats(vdev, &stats);
7722 	sinfo->tx_bytes = stats.tx_bytes;
7723 	sinfo->rx_bytes = stats.rx_bytes;
7724 	sinfo->rx_packets = stats.rx_packets;
7725 	wlan_hdd_update_mlo_peer_stats(link_info, sinfo);
7726 
7727 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7728 
7729 	qdf_mem_copy(&sta_ctx->conn_info.txrate,
7730 		     &sinfo->txrate, sizeof(sinfo->txrate));
7731 	qdf_mem_copy(&sta_ctx->cache_conn_info.txrate,
7732 		     &sinfo->txrate, sizeof(sinfo->txrate));
7733 
7734 	qdf_mem_copy(&sta_ctx->conn_info.rxrate,
7735 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
7736 
7737 	sinfo->filled |= HDD_INFO_TX_BITRATE |
7738 			 HDD_INFO_RX_BITRATE |
7739 			 HDD_INFO_TX_BYTES   |
7740 			 HDD_INFO_RX_BYTES   |
7741 			 HDD_INFO_RX_PACKETS;
7742 
7743 	if (tx_rate_flags & TX_RATE_LEGACY) {
7744 		hdd_debug("[TX: Reporting legacy rate %d pkt cnt %d]-"
7745 			  "[RX: Reporting legacy rate %d pkt cnt %d]",
7746 			  sinfo->txrate.legacy, sinfo->tx_packets,
7747 			  sinfo->rxrate.legacy, sinfo->rx_packets);
7748 	} else {
7749 		hdd_debug("[TX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]-"
7750 			  "[RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]",
7751 			  sinfo->txrate.mcs, sinfo->txrate.flags,
7752 			  sinfo->tx_packets, sinfo->txrate.nss,
7753 			  sinfo->txrate.bw, sinfo->rxrate.mcs,
7754 			  sinfo->rxrate.flags, sinfo->rx_packets,
7755 			  sinfo->rxrate.nss, sinfo->rxrate.bw);
7756 	}
7757 
7758 	return 0;
7759 }
7760 
7761 /**
7762  * wlan_hdd_get_sta_stats() - get aggregate STA stats
7763  * @link_info: Link info pointer of STA adapter to get stats for
7764  * @mac: mac address of sta
7765  * @sinfo: kernel station_info struct to populate
7766  *
7767  * Fetch the vdev-level aggregate stats for the given STA adapter. This is to
7768  * support "station dump" and "station get" for STA vdevs
7769  *
7770  * Return: errno
7771  */
wlan_hdd_get_sta_stats(struct wlan_hdd_link_info * link_info,const uint8_t * mac,struct station_info * sinfo)7772 static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
7773 				  const uint8_t *mac,
7774 				  struct station_info *sinfo)
7775 {
7776 	struct hdd_adapter *adapter = link_info->adapter;
7777 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7778 	struct hdd_station_ctx *sta_ctx;
7779 	uint8_t *link_mac;
7780 	int32_t rcpi_value;
7781 
7782 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
7783 		   TRACE_CODE_HDD_CFG80211_GET_STA,
7784 		   link_info->vdev_id, 0);
7785 
7786 	if (link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX) {
7787 		wlan_hdd_update_sinfo(sinfo, link_info);
7788 		hdd_debug_rl("Sending Cached stats for standby link");
7789 		return 0;
7790 	}
7791 
7792 	if (!hdd_cm_is_vdev_associated(link_info)) {
7793 		hdd_debug("Not associated");
7794 		/*To keep GUI happy */
7795 		return 0;
7796 	}
7797 
7798 	if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id)) {
7799 		hdd_debug("Roam sync is in progress, cannot continue with this request");
7800 		/*
7801 		 * supplicant reports very low rssi to upper layer
7802 		 * and handover happens to cellular.
7803 		 * send the cached rssi when get_station
7804 		 */
7805 		sinfo->signal = link_info->rssi;
7806 		sinfo->filled |= HDD_INFO_SIGNAL;
7807 		return 0;
7808 	}
7809 
7810 	if (hdd_ctx->rcpi_enabled)
7811 		wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
7812 				  RCPI_MEASUREMENT_TYPE_AVG_MGMT);
7813 
7814 	wlan_hdd_get_station_stats(link_info);
7815 
7816 	wlan_hdd_get_peer_rx_rate_stats(link_info);
7817 
7818 	wlan_hdd_update_rssi(link_info, sinfo);
7819 
7820 	/*
7821 	 * we notify connect to lpass here instead of during actual
7822 	 * connect processing because rssi info is not accurate during
7823 	 * actual connection.  lpass will ensure the notification is
7824 	 * only processed once per association.
7825 	 */
7826 	hdd_lpass_notify_connect(link_info);
7827 
7828 	if (wlan_hdd_update_rate_info(link_info, sinfo))
7829 		/* Keep GUI happy */
7830 		return 0;
7831 
7832 	hdd_fill_fcs_and_mpdu_count(link_info, sinfo);
7833 
7834 	hdd_wlan_fill_per_chain_rssi_stats(sinfo, link_info);
7835 
7836 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7837 	link_mac = sta_ctx->conn_info.bssid.bytes;
7838 	hdd_nofl_debug("Sending station stats for link " QDF_MAC_ADDR_FMT,
7839 		       QDF_MAC_ADDR_REF(link_mac));
7840 
7841 	wlan_hdd_copy_sinfo_to_link_info(link_info, sinfo);
7842 
7843 	hdd_exit();
7844 
7845 	return 0;
7846 }
7847 
7848 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
7849 /*
7850  * wlan_hdd_update_mlo_rate_info() - Populate mlo station stats rate info
7851  * @hdd_sinfo: Pointer to hdd stats station info struct
7852  * @sinfo: Pointer to kernel station info struct
7853  *
7854  * Return: none
7855  */
7856 static void
wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info * hdd_sinfo,struct station_info * sinfo)7857 wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info *hdd_sinfo,
7858 			      struct station_info *sinfo)
7859 {
7860 	uint8_t i;
7861 
7862 	hdd_sinfo->signal = sinfo->signal;
7863 	hdd_sinfo->signal_avg = sinfo->signal_avg;
7864 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
7865 		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
7866 
7867 	qdf_mem_copy(&hdd_sinfo->txrate,
7868 		     &sinfo->txrate, sizeof(sinfo->txrate));
7869 
7870 	qdf_mem_copy(&hdd_sinfo->rxrate,
7871 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
7872 }
7873 
7874 /*
7875  * wlan_hdd_update_mlo_sinfo() - Populate mlo stats station info
7876  * @link_info: Link info pointer of STA adapter
7877  * @hdd_sinfo: Pointer to hdd stats station info struct
7878  * @sinfo: Pointer to kernel station info struct
7879  *
7880  * Return: none
7881  */
7882 static void
wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info * link_info,struct wlan_hdd_station_stats_info * hdd_sinfo,struct station_info * sinfo)7883 wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info,
7884 			  struct wlan_hdd_station_stats_info *hdd_sinfo,
7885 			  struct station_info *sinfo)
7886 {
7887 	struct hdd_station_ctx *sta_ctx;
7888 
7889 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7890 
7891 	if (!link_info->is_mlo_vdev_active)
7892 		hdd_nofl_debug("vdev_id[%d] is inactive", link_info->vdev_id);
7893 
7894 	/* Update the rate info for link with best RSSI */
7895 	if (sinfo->signal > hdd_sinfo->signal) {
7896 		hdd_nofl_debug("Updating rates for link_id %d",
7897 			       sta_ctx->conn_info.ieee_link_id);
7898 		wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo);
7899 	}
7900 
7901 	/* Send cumulative Tx/Rx packets and bytes data
7902 	 * of all active links to userspace
7903 	 */
7904 	hdd_sinfo->rx_bytes += sinfo->rx_bytes;
7905 	hdd_sinfo->tx_bytes += sinfo->tx_bytes;
7906 	hdd_sinfo->rx_packets += sinfo->rx_packets;
7907 	hdd_sinfo->tx_packets += sinfo->tx_packets;
7908 	hdd_sinfo->tx_retries += sinfo->tx_retries;
7909 	hdd_sinfo->tx_failed += sinfo->tx_failed;
7910 	hdd_sinfo->rx_mpdu_count += sinfo->rx_mpdu_count;
7911 	hdd_sinfo->fcs_err_count += sinfo->fcs_err_count;
7912 }
7913 
7914 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
7915 /**
7916  * wlan_hdd_get_mlo_sta_stats - get aggregate STA stats for MLO
7917  * @adapter: HDD adapter
7918  * @mac: mac address
7919  * @sinfo: kernel station_info struct to populate
7920  *
7921  * Return: 0 on success; errno on failure
7922  */
wlan_hdd_get_mlo_sta_stats(struct hdd_adapter * adapter,const uint8_t * mac,struct station_info * sinfo)7923 static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7924 				      const uint8_t *mac,
7925 				      struct station_info *sinfo)
7926 {
7927 	struct hdd_adapter *ml_adapter, *link_adapter;
7928 	struct hdd_mlo_adapter_info *mlo_adapter_info;
7929 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
7930 	uint8_t i;
7931 
7932 	/* Initialize the signal value to a default RSSI of -128dBm */
7933 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
7934 
7935 	ml_adapter = adapter;
7936 	if (hdd_adapter_is_link_adapter(ml_adapter))
7937 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
7938 
7939 	wlan_hdd_get_sta_stats(ml_adapter->deflink, mac, sinfo);
7940 	wlan_hdd_update_mlo_sinfo(ml_adapter->deflink, &hdd_sinfo, sinfo);
7941 
7942 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
7943 	for (i = 0; i < WLAN_MAX_MLD; i++) {
7944 		link_adapter = mlo_adapter_info->link_adapter[i];
7945 		if (!link_adapter ||
7946 		    hdd_adapter_is_associated_with_ml_adapter(link_adapter))
7947 			continue;
7948 
7949 		wlan_hdd_get_sta_stats(link_adapter->deflink, mac, sinfo);
7950 		wlan_hdd_update_mlo_sinfo(link_adapter->deflink, &hdd_sinfo,
7951 					  sinfo);
7952 	}
7953 
7954 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
7955 	hdd_nofl_debug("Sending aggregated mlo station stats");
7956 
7957 	hdd_exit();
7958 
7959 	return 0;
7960 }
7961 #else
wlan_hdd_get_mlo_sta_stats(struct hdd_adapter * adapter,const uint8_t * mac,struct station_info * sinfo)7962 static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7963 				      const uint8_t *mac,
7964 				      struct station_info *sinfo)
7965 {
7966 	struct wlan_hdd_link_info *link_info;
7967 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
7968 	struct hdd_station_ctx *sta_ctx;
7969 
7970 	/* Initialize the signal value to a default RSSI of -128dBm */
7971 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
7972 
7973 	hdd_adapter_for_each_link_info(adapter, link_info) {
7974 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7975 		if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID)
7976 			continue;
7977 		wlan_hdd_get_sta_stats(link_info, mac, sinfo);
7978 		wlan_hdd_update_mlo_sinfo(link_info, &hdd_sinfo, sinfo);
7979 	}
7980 
7981 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
7982 	hdd_nofl_debug("Sending aggregated mlo station stats");
7983 
7984 	hdd_exit();
7985 
7986 	return 0;
7987 }
7988 #endif
7989 #else
wlan_hdd_get_mlo_sta_stats(struct hdd_adapter * adapter,const uint8_t * mac,struct station_info * sinfo)7990 static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7991 				      const uint8_t *mac,
7992 				      struct station_info *sinfo)
7993 {
7994 	return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
7995 }
7996 #endif
7997 
7998 /*
7999  * wlan_is_mlo_aggregated_stats_allowed() - Is aggregated stats requested
8000  * @adapter: HDD adapter
8001  * @mac: mac address
8002  *
8003  * Return: True if req is on mld_mac and FW supports per link stats, else False
8004  */
8005 static bool
wlan_is_mlo_aggregated_stats_allowed(struct hdd_adapter * adapter,const uint8_t * mac)8006 wlan_is_mlo_aggregated_stats_allowed(struct hdd_adapter *adapter,
8007 				     const uint8_t *mac)
8008 {
8009 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8010 	bool is_mld_req = false;
8011 	bool per_link_stats_cap = false;
8012 	struct qdf_mac_addr peer_mld_mac;
8013 	QDF_STATUS status;
8014 
8015 	if (!hdd_ctx) {
8016 		hdd_err("invalid hdd_ctx");
8017 		return false;
8018 	}
8019 
8020 	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink, &peer_mld_mac);
8021 	if (QDF_IS_STATUS_ERROR(status)) {
8022 		hdd_err_rl("mlo_vdev_stats: failed to get bss peer mld mac");
8023 		return false;
8024 	}
8025 
8026 	is_mld_req = qdf_is_macaddr_equal(&peer_mld_mac,
8027 					  (struct qdf_mac_addr *)mac);
8028 	per_link_stats_cap = wlan_hdd_is_per_link_stats_supported(hdd_ctx);
8029 
8030 	if (is_mld_req && per_link_stats_cap) {
8031 		hdd_debug_rl("Fetching Aggregated station stats");
8032 		return true;
8033 	}
8034 
8035 	return false;
8036 }
8037 
8038 /**
8039  * wlan_hdd_send_mlo_station_stats() - send station stats to userspace
8040  * @adapter: Pointer to hdd adapter
8041  * @hdd_ctx: Pointer to hdd context
8042  * @mac: mac address
8043  * @sinfo: kernel station_info struct to populate
8044  *
8045  * Return: 0 on success; errno on failure
8046  */
wlan_hdd_send_mlo_station_stats(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx,const uint8_t * mac,struct station_info * sinfo)8047 static int wlan_hdd_send_mlo_station_stats(struct hdd_adapter *adapter,
8048 					   struct hdd_context *hdd_ctx,
8049 					   const uint8_t *mac,
8050 					   struct station_info *sinfo)
8051 {
8052 	struct wlan_hdd_link_info *link_info;
8053 
8054 	if (!wlan_hdd_is_mlo_connection(adapter->deflink)) {
8055 		hdd_nofl_debug("Fetching station stats for legacy connection");
8056 		return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
8057 	}
8058 
8059 	link_info = hdd_get_link_info_by_bssid(hdd_ctx, mac);
8060 	if (!link_info) {
8061 		if (wlan_is_mlo_aggregated_stats_allowed(adapter, mac))
8062 			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
8063 
8064 		hdd_debug_rl("Invalid bssid");
8065 		return -EINVAL;
8066 	}
8067 	return wlan_hdd_get_sta_stats(link_info, mac, sinfo);
8068 }
8069 
8070 /**
8071  * __wlan_hdd_cfg80211_get_station() - get station statistics
8072  * @wiphy: Pointer to wiphy
8073  * @dev: Pointer to network device
8074  * @mac: Pointer to mac
8075  * @sinfo: Pointer to station info
8076  *
8077  * Return: 0 for success, non-zero for failure
8078  */
__wlan_hdd_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const uint8_t * mac,struct station_info * sinfo)8079 static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8080 					   struct net_device *dev,
8081 					   const uint8_t *mac,
8082 					   struct station_info *sinfo)
8083 {
8084 	int errno;
8085 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8086 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8087 	struct hdd_station_info *stainfo;
8088 	bool get_peer_info_enable;
8089 	QDF_STATUS qdf_status;
8090 	struct wlan_hdd_link_info *link_info = adapter->deflink;
8091 
8092 	hdd_enter_dev(dev);
8093 
8094 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
8095 		hdd_err("Command not allowed in FTM mode");
8096 		return -EINVAL;
8097 	}
8098 
8099 	if (wlan_hdd_validate_context(hdd_ctx))
8100 		return -EINVAL;
8101 
8102 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
8103 		return -EINVAL;
8104 
8105 	hdd_nofl_debug("Stats request on MAC: " QDF_MAC_ADDR_FMT,
8106 		       QDF_MAC_ADDR_REF(mac));
8107 
8108 	if (!mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mac)) {
8109 		hdd_err("Invalid MAC addr");
8110 		return -EINVAL;
8111 	}
8112 
8113 	if (adapter->device_mode == QDF_SAP_MODE ||
8114 	    adapter->device_mode == QDF_P2P_GO_MODE) {
8115 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
8116 				hdd_ctx->psoc, &get_peer_info_enable);
8117 		if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
8118 			stainfo = hdd_get_sta_info_by_mac(
8119 					&adapter->sta_info_list, mac,
8120 					STA_INFO_WLAN_HDD_CFG80211_GET_STATION);
8121 			if (!stainfo) {
8122 				hdd_debug("Peer " QDF_MAC_ADDR_FMT " not found",
8123 					  QDF_MAC_ADDR_REF(mac));
8124 				return -EINVAL;
8125 			}
8126 
8127 			errno = wlan_hdd_get_station_remote(wiphy, dev,
8128 							    stainfo, sinfo);
8129 			hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo,
8130 					     true,
8131 					STA_INFO_WLAN_HDD_CFG80211_GET_STATION
8132 					);
8133 			if (!errno)
8134 				return 0;
8135 		}
8136 		return wlan_hdd_get_sap_stats(link_info, sinfo);
8137 	}
8138 
8139 	return wlan_hdd_send_mlo_station_stats(adapter, hdd_ctx, mac, sinfo);
8140 }
8141 
8142 /**
8143  * _wlan_hdd_cfg80211_get_station() - get station statistics
8144  *
8145  * @wiphy: Pointer to wiphy
8146  * @dev: Pointer to network device
8147  * @mac: Pointer to mac
8148  * @sinfo: Pointer to station info
8149  *
8150  * This API tries runtime PM suspend right away after getting station
8151  * statistics.
8152  *
8153  * Return: 0 for success, non-zero for failure
8154  */
_wlan_hdd_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const uint8_t * mac,struct station_info * sinfo)8155 static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8156 					  struct net_device *dev,
8157 					  const uint8_t *mac,
8158 					  struct station_info *sinfo)
8159 {
8160 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8161 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8162 	int errno;
8163 	QDF_STATUS status;
8164 
8165 	errno = wlan_hdd_validate_context(hdd_ctx);
8166 	if (errno)
8167 		return errno;
8168 
8169 	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
8170 		hdd_debug("Link Switch in progress, can't process request");
8171 		return -EBUSY;
8172 	}
8173 
8174 	status = wlan_hdd_stats_request_needed(adapter);
8175 	if (QDF_IS_STATUS_ERROR(status)) {
8176 		if (status == QDF_STATUS_E_ALREADY)
8177 			get_station_fw_request_needed = false;
8178 		else
8179 			return -EINVAL;
8180 	}
8181 
8182 	if (get_station_fw_request_needed) {
8183 		errno = wlan_hdd_qmi_get_sync_resume();
8184 		if (errno) {
8185 			hdd_err("qmi sync resume failed: %d", errno);
8186 			return errno;
8187 		}
8188 	}
8189 
8190 	errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
8191 
8192 	if (get_station_fw_request_needed)
8193 		wlan_hdd_qmi_put_suspend();
8194 
8195 	get_station_fw_request_needed = true;
8196 
8197 	return errno;
8198 }
8199 
8200 /**
8201  * wlan_hdd_cfg80211_get_station() - get station statistics
8202  * @wiphy: Pointer to wiphy
8203  * @dev: Pointer to network device
8204  * @mac: Pointer to mac
8205  * @sinfo: Pointer to station info
8206  *
8207  * Return: 0 for success, non-zero for failure
8208  */
wlan_hdd_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const uint8_t * mac,struct station_info * sinfo)8209 int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8210 				  struct net_device *dev, const uint8_t *mac,
8211 				  struct station_info *sinfo)
8212 {
8213 	int errno;
8214 	struct osif_vdev_sync *vdev_sync;
8215 
8216 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8217 	if (errno)
8218 		return errno;
8219 
8220 	errno = _wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
8221 
8222 	osif_vdev_sync_op_stop(vdev_sync);
8223 
8224 	return errno;
8225 }
8226 
8227 /**
8228  * __wlan_hdd_cfg80211_dump_station() - dump station statistics
8229  * @wiphy: Pointer to wiphy
8230  * @dev: Pointer to network device
8231  * @idx: variable to station index, kernel iterate all stations over idx
8232  * @mac: Pointer to mac
8233  * @sinfo: Pointer to station info
8234  *
8235  * Return: 0 for success, non-zero for failure
8236  */
__wlan_hdd_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * mac,struct station_info * sinfo)8237 static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
8238 				struct net_device *dev,
8239 				int idx, u8 *mac,
8240 				struct station_info *sinfo)
8241 {
8242 	int errno;
8243 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8244 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8245 	struct hdd_station_info *stainfo;
8246 	bool get_peer_info_enable;
8247 	QDF_STATUS qdf_status;
8248 
8249 	hdd_debug("idx: %d", idx);
8250 
8251 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
8252 		hdd_err("Command not allowed in FTM mode");
8253 		return -EINVAL;
8254 	}
8255 
8256 	if (wlan_hdd_validate_context(hdd_ctx))
8257 		return -EINVAL;
8258 
8259 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
8260 		return -EINVAL;
8261 
8262 	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
8263 		hdd_debug("Link Switch in progress, can't process request");
8264 		return -EBUSY;
8265 	}
8266 
8267 	if (adapter->device_mode == QDF_SAP_MODE ||
8268 	    adapter->device_mode == QDF_P2P_GO_MODE) {
8269 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
8270 				hdd_ctx->psoc, &get_peer_info_enable);
8271 		if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
8272 			stainfo = hdd_get_sta_info_by_id(
8273 					&adapter->sta_info_list,
8274 					idx,
8275 					STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION
8276 					);
8277 			if (!stainfo) {
8278 				hdd_err("peer idx %d NOT FOUND", idx);
8279 				return -ENOENT;
8280 			}
8281 
8282 			qdf_mem_copy(mac, &stainfo->sta_mac.bytes,
8283 				     QDF_MAC_ADDR_SIZE);
8284 			errno = wlan_hdd_get_station_remote(wiphy, dev,
8285 							    stainfo, sinfo);
8286 			hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo,
8287 					     true,
8288 					STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION
8289 					);
8290 		} else {
8291 			errno = -EINVAL;
8292 			hdd_err("sap get peer info disabled!");
8293 		}
8294 	} else {
8295 		if (idx != 0)
8296 			return -ENOENT;
8297 
8298 		qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
8299 
8300 		if (wlan_hdd_is_mlo_connection(adapter->deflink) &&
8301 		    wlan_hdd_is_per_link_stats_supported(hdd_ctx))
8302 			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
8303 
8304 		hdd_nofl_debug("Sending Assoc Link stats");
8305 		errno = wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
8306 	}
8307 	return errno;
8308 }
8309 
8310 /**
8311  * wlan_hdd_cfg80211_dump_station() - dump station statistics
8312  * @wiphy: Pointer to wiphy
8313  * @dev: Pointer to network device
8314  * @idx: variable to determine whether to get stats or not
8315  * @mac: Pointer to mac
8316  * @sinfo: Pointer to station info
8317  *
8318  * Return: 0 for success, non-zero for failure
8319  */
wlan_hdd_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * mac,struct station_info * sinfo)8320 int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
8321 				struct net_device *dev,
8322 				int idx, u8 *mac,
8323 				struct station_info *sinfo)
8324 {
8325 	int errno;
8326 	struct osif_vdev_sync *vdev_sync;
8327 
8328 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8329 	if (errno)
8330 		return errno;
8331 
8332 	errno = wlan_hdd_qmi_get_sync_resume();
8333 	if (errno) {
8334 		hdd_err("qmi sync resume failed: %d", errno);
8335 		goto end;
8336 	}
8337 
8338 	errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
8339 
8340 	wlan_hdd_qmi_put_suspend();
8341 
8342 end:
8343 	osif_vdev_sync_op_stop(vdev_sync);
8344 
8345 	return errno;
8346 }
8347 
8348 /**
8349  * hdd_get_stats() - Function to retrieve interface statistics
8350  * @dev: pointer to network device
8351  *
8352  * This function is the ndo_get_stats method for all netdevs
8353  * registered with the kernel
8354  *
8355  * Return: pointer to net_device_stats structure
8356  */
hdd_get_stats(struct net_device * dev)8357 struct net_device_stats *hdd_get_stats(struct net_device *dev)
8358 {
8359 	return (struct net_device_stats *)ucfg_dp_get_dev_stats(dev);
8360 }
8361 
8362 /*
8363  * FW sends value of cycle_count, rx_clear_count and tx_frame_count in usec.
8364  */
8365 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
wlan_fill_survey_result(struct survey_info * survey,int opfreq,struct scan_chan_info * chan_info,struct ieee80211_channel * channels)8366 static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
8367 				    struct scan_chan_info *chan_info,
8368 				    struct ieee80211_channel *channels)
8369 {
8370 	if (channels->center_freq != (uint16_t)chan_info->freq)
8371 		return false;
8372 
8373 	survey->channel = channels;
8374 	survey->noise = chan_info->noise_floor;
8375 	survey->filled = 0;
8376 
8377 	if (chan_info->noise_floor)
8378 		survey->filled |= SURVEY_INFO_NOISE_DBM;
8379 
8380 	if (opfreq == chan_info->freq)
8381 		survey->filled |= SURVEY_INFO_IN_USE;
8382 
8383 	survey->time = chan_info->cycle_count;
8384 	survey->time_busy = chan_info->rx_clear_count;
8385 	survey->time_tx = chan_info->tx_frame_count;
8386 
8387 	survey->filled |= SURVEY_INFO_TIME |
8388 			  SURVEY_INFO_TIME_BUSY |
8389 			  SURVEY_INFO_TIME_TX;
8390 	return true;
8391 }
8392 #else
wlan_fill_survey_result(struct survey_info * survey,int opfreq,struct scan_chan_info * chan_info,struct ieee80211_channel * channels)8393 static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
8394 				    struct scan_chan_info *chan_info,
8395 				    struct ieee80211_channel *channels)
8396 {
8397 	if (channels->center_freq != (uint16_t)chan_info->freq)
8398 		return false;
8399 
8400 	survey->channel = channels;
8401 	survey->noise = chan_info->noise_floor;
8402 	survey->filled = 0;
8403 
8404 	if (chan_info->noise_floor)
8405 		survey->filled |= SURVEY_INFO_NOISE_DBM;
8406 
8407 	if (opfreq == chan_info->freq)
8408 		survey->filled |= SURVEY_INFO_IN_USE;
8409 
8410 	survey->channel_time = chan_info->cycle_count;
8411 	survey->channel_time_busy = chan_info->rx_clear_count;
8412 	survey->channel_time_tx = chan_info->tx_frame_count;
8413 
8414 	survey->filled |= SURVEY_INFO_CHANNEL_TIME |
8415 			  SURVEY_INFO_CHANNEL_TIME_BUSY |
8416 			  SURVEY_INFO_CHANNEL_TIME_TX;
8417 	return true;
8418 }
8419 #endif
8420 
wlan_hdd_update_survey_info(struct wiphy * wiphy,struct hdd_adapter * adapter,struct survey_info * survey,int idx)8421 static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
8422 					struct hdd_adapter *adapter,
8423 					struct survey_info *survey, int idx)
8424 {
8425 	bool filled = false;
8426 	int i, j = 0;
8427 	uint32_t opfreq = 0; /* Initialization Required */
8428 	struct hdd_context *hdd_ctx;
8429 
8430 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8431 	sme_get_operation_channel(hdd_ctx->mac_handle, &opfreq,
8432 				  adapter->deflink->vdev_id);
8433 
8434 	mutex_lock(&hdd_ctx->chan_info_lock);
8435 
8436 	for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
8437 		if (!wiphy->bands[i])
8438 			continue;
8439 
8440 		for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
8441 			struct ieee80211_supported_band *band = wiphy->bands[i];
8442 
8443 			filled = wlan_fill_survey_result(survey, opfreq,
8444 				&hdd_ctx->chan_info[idx],
8445 				&band->channels[j]);
8446 		}
8447 	}
8448 	mutex_unlock(&hdd_ctx->chan_info_lock);
8449 
8450 	return filled;
8451 }
8452 
8453 /**
8454  * __wlan_hdd_cfg80211_dump_survey() - get survey related info
8455  * @wiphy: Pointer to wiphy
8456  * @dev: Pointer to network device
8457  * @idx: Index
8458  * @survey: Pointer to survey info
8459  *
8460  * Return: 0 for success, non-zero for failure
8461  */
__wlan_hdd_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)8462 static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
8463 					   struct net_device *dev,
8464 					   int idx, struct survey_info *survey)
8465 {
8466 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8467 	struct hdd_context *hdd_ctx;
8468 	int status;
8469 	bool filled = false;
8470 
8471 	if (idx > NUM_CHANNELS - 1)
8472 		return -ENOENT;
8473 
8474 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8475 	status = wlan_hdd_validate_context(hdd_ctx);
8476 	if (0 != status)
8477 		return status;
8478 
8479 	if (!hdd_ctx->chan_info) {
8480 		hdd_debug("chan_info is NULL");
8481 		return -EINVAL;
8482 	}
8483 
8484 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
8485 		hdd_err("Command not allowed in FTM mode");
8486 		return -EINVAL;
8487 	}
8488 
8489 	if (!ucfg_scan_is_snr_monitor_enabled(hdd_ctx->psoc))
8490 		return -ENONET;
8491 
8492 	if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
8493 		hdd_debug("Roaming in progress, hence return");
8494 		return -ENONET;
8495 	}
8496 
8497 	filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
8498 
8499 	if (!filled)
8500 		return -ENOENT;
8501 
8502 	return 0;
8503 }
8504 
8505 /**
8506  * wlan_hdd_cfg80211_dump_survey() - get survey related info
8507  * @wiphy: Pointer to wiphy
8508  * @dev: Pointer to network device
8509  * @idx: Index
8510  * @survey: Pointer to survey info
8511  *
8512  * Return: 0 for success, non-zero for failure
8513  */
wlan_hdd_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)8514 int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
8515 				  struct net_device *dev,
8516 				  int idx, struct survey_info *survey)
8517 {
8518 	int errno;
8519 	struct osif_vdev_sync *vdev_sync;
8520 
8521 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8522 	if (errno)
8523 		return errno;
8524 
8525 	errno = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
8526 
8527 	osif_vdev_sync_op_stop(vdev_sync);
8528 
8529 	return errno;
8530 }
8531 
8532 /**
8533  * hdd_display_hif_stats() - display hif stats
8534  *
8535  * Return: none
8536  *
8537  */
hdd_display_hif_stats(void)8538 void hdd_display_hif_stats(void)
8539 {
8540 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
8541 
8542 	if (!hif_ctx)
8543 		return;
8544 
8545 	hif_display_stats(hif_ctx);
8546 }
8547 
8548 /**
8549  * hdd_clear_hif_stats() - clear hif stats
8550  *
8551  * Return: none
8552  */
hdd_clear_hif_stats(void)8553 void hdd_clear_hif_stats(void)
8554 {
8555 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
8556 
8557 	if (!hif_ctx)
8558 		return;
8559 	hif_clear_stats(hif_ctx);
8560 }
8561 
8562 /**
8563  * hdd_is_rcpi_applicable() - validates RCPI request
8564  * @adapter: adapter upon which the measurement is requested
8565  * @mac_addr: peer addr for which measurement is requested
8566  * @rcpi_value: pointer to where the RCPI should be returned
8567  * @reassoc: used to return cached RCPI during reassoc
8568  *
8569  * Return: true for success, false for failure
8570  */
8571 
hdd_is_rcpi_applicable(struct hdd_adapter * adapter,struct qdf_mac_addr * mac_addr,int32_t * rcpi_value,bool * reassoc)8572 static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
8573 				   struct qdf_mac_addr *mac_addr,
8574 				   int32_t *rcpi_value,
8575 				   bool *reassoc)
8576 {
8577 	struct hdd_station_ctx *hdd_sta_ctx;
8578 
8579 	if (adapter->device_mode == QDF_STA_MODE ||
8580 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
8581 		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
8582 		if (!hdd_cm_is_vdev_associated(adapter->deflink))
8583 			return false;
8584 
8585 		if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
8586 			/* return the cached rcpi, if mac addr matches */
8587 			hdd_debug("Roaming in progress, return cached RCPI");
8588 			if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
8589 					 mac_addr, sizeof(*mac_addr))) {
8590 				*rcpi_value = adapter->rcpi.rcpi;
8591 				*reassoc = true;
8592 				return true;
8593 			}
8594 			return false;
8595 		}
8596 
8597 		if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssid,
8598 				sizeof(*mac_addr))) {
8599 			hdd_err("mac addr is different from bssid connected");
8600 			return false;
8601 		}
8602 	} else if (adapter->device_mode == QDF_SAP_MODE ||
8603 		   adapter->device_mode == QDF_P2P_GO_MODE) {
8604 		if (!test_bit(SOFTAP_BSS_STARTED,
8605 			      &adapter->deflink->link_flags)) {
8606 			hdd_err("Invalid rcpi request, softap not started");
8607 			return false;
8608 		}
8609 
8610 		/* check if peer mac addr is associated to softap */
8611 		if (!hdd_is_peer_associated(adapter, mac_addr)) {
8612 			hdd_err("invalid peer mac-addr: not associated");
8613 			return false;
8614 		}
8615 	} else {
8616 		hdd_err("Invalid rcpi request");
8617 		return false;
8618 	}
8619 
8620 	*reassoc = false;
8621 	return true;
8622 }
8623 
8624 /**
8625  * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
8626  * @context: Pointer to rcpi context
8627  * @mac_addr: peer MAC address
8628  * @rcpi: RCPI response
8629  * @status: QDF_STATUS of the request
8630  *
8631  * Return: None
8632  */
wlan_hdd_get_rcpi_cb(void * context,struct qdf_mac_addr mac_addr,int32_t rcpi,QDF_STATUS status)8633 static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
8634 				 int32_t rcpi, QDF_STATUS status)
8635 {
8636 	struct osif_request *request;
8637 	struct rcpi_info *priv;
8638 
8639 	if (!context) {
8640 		hdd_err("No rcpi context");
8641 		return;
8642 	}
8643 
8644 	request = osif_request_get(context);
8645 	if (!request) {
8646 		hdd_err("Obsolete RCPI request");
8647 		return;
8648 	}
8649 
8650 	priv = osif_request_priv(request);
8651 	priv->mac_addr = mac_addr;
8652 
8653 	if (!QDF_IS_STATUS_SUCCESS(status)) {
8654 		priv->rcpi = 0;
8655 		hdd_err("Error in computing RCPI");
8656 	} else {
8657 		priv->rcpi = rcpi;
8658 	}
8659 
8660 	osif_request_complete(request);
8661 	osif_request_put(request);
8662 }
8663 
8664 /**
8665  * wlan_hdd_get_rcpi() - local function to get RCPI
8666  * @adapter: adapter upon which the measurement is requested
8667  * @mac: peer addr for which measurement is requested
8668  * @rcpi_value: pointer to where the RCPI should be returned
8669  * @measurement_type: type of rcpi measurement
8670  *
8671  * Return: 0 for success, non-zero for failure
8672  */
wlan_hdd_get_rcpi(struct hdd_adapter * adapter,uint8_t * mac,int32_t * rcpi_value,enum rcpi_measurement_type measurement_type)8673 int wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
8674 		      uint8_t *mac,
8675 		      int32_t *rcpi_value,
8676 		      enum rcpi_measurement_type measurement_type)
8677 {
8678 	struct hdd_context *hdd_ctx;
8679 	int status = 0, ret = 0;
8680 	struct qdf_mac_addr mac_addr;
8681 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
8682 	struct sme_rcpi_req *rcpi_req;
8683 	void *cookie;
8684 	struct rcpi_info *priv;
8685 	struct osif_request *request;
8686 	static const struct osif_request_params params = {
8687 		.priv_size = sizeof(*priv),
8688 		.timeout_ms = WLAN_WAIT_TIME_RCPI,
8689 	};
8690 	bool reassoc;
8691 
8692 	hdd_enter();
8693 
8694 	/* initialize the rcpi value to zero, useful in error cases */
8695 	*rcpi_value = 0;
8696 
8697 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
8698 		hdd_err("Command not allowed in FTM mode");
8699 		return -EINVAL;
8700 	}
8701 
8702 	if (!adapter) {
8703 		hdd_warn("adapter context is NULL");
8704 		return -EINVAL;
8705 	}
8706 
8707 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8708 	status = wlan_hdd_validate_context(hdd_ctx);
8709 	if (status)
8710 		return -EINVAL;
8711 
8712 	if (!hdd_ctx->rcpi_enabled) {
8713 		hdd_debug("RCPI not supported");
8714 		return -EINVAL;
8715 	}
8716 
8717 	if (!mac) {
8718 		hdd_warn("RCPI peer mac-addr is NULL");
8719 		return -EINVAL;
8720 	}
8721 
8722 	qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
8723 
8724 	if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
8725 		return -EINVAL;
8726 	if (reassoc)
8727 		return 0;
8728 
8729 	rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
8730 	if (!rcpi_req)
8731 		return -EINVAL;
8732 
8733 	request = osif_request_alloc(&params);
8734 	if (!request) {
8735 		hdd_err("Request allocation failure");
8736 		qdf_mem_free(rcpi_req);
8737 		return -ENOMEM;
8738 	}
8739 	cookie = osif_request_cookie(request);
8740 
8741 	rcpi_req->mac_addr = mac_addr;
8742 	rcpi_req->session_id = adapter->deflink->vdev_id;
8743 	rcpi_req->measurement_type = measurement_type;
8744 	rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
8745 	rcpi_req->rcpi_context = cookie;
8746 
8747 	qdf_status = sme_get_rcpi(hdd_ctx->mac_handle, rcpi_req);
8748 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
8749 		hdd_err("Unable to retrieve RCPI");
8750 		status = qdf_status_to_os_return(qdf_status);
8751 		goto out;
8752 	}
8753 
8754 	/* request was sent -- wait for the response */
8755 	ret = osif_request_wait_for_response(request);
8756 	if (ret) {
8757 		hdd_err("SME timed out while retrieving RCPI");
8758 		status = -EINVAL;
8759 		goto out;
8760 	}
8761 
8762 	/* update the adapter with the fresh results */
8763 	priv = osif_request_priv(request);
8764 	adapter->rcpi.mac_addr = priv->mac_addr;
8765 	adapter->rcpi.rcpi = priv->rcpi;
8766 	if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
8767 		hdd_err("mis match of mac addr from call-back");
8768 		status = -EINVAL;
8769 		goto out;
8770 	}
8771 
8772 	*rcpi_value = adapter->rcpi.rcpi;
8773 	hdd_debug("RCPI = %d", *rcpi_value);
8774 out:
8775 	qdf_mem_free(rcpi_req);
8776 	osif_request_put(request);
8777 
8778 	hdd_exit();
8779 	return status;
8780 }
8781 
8782 #ifdef WLAN_FEATURE_MIB_STATS
wlan_hdd_get_mib_stats(struct hdd_adapter * adapter)8783 QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter)
8784 {
8785 	int ret = 0;
8786 	struct stats_event *stats;
8787 	struct wlan_objmgr_vdev *vdev;
8788 
8789 	if (!adapter) {
8790 		hdd_err("Invalid context, adapter");
8791 		return QDF_STATUS_E_FAULT;
8792 	}
8793 
8794 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
8795 					   WLAN_OSIF_STATS_ID);
8796 	if (!vdev)
8797 		return QDF_STATUS_E_FAULT;
8798 
8799 	stats = wlan_cfg80211_mc_cp_stats_get_mib_stats(vdev, &ret);
8800 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
8801 	if (ret || !stats) {
8802 		wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
8803 		return ret;
8804 	}
8805 
8806 	hdd_debugfs_process_mib_stats(adapter, stats);
8807 
8808 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
8809 	return ret;
8810 }
8811 #endif
8812 
wlan_hdd_get_rssi(struct wlan_hdd_link_info * link_info,int8_t * rssi_value)8813 QDF_STATUS wlan_hdd_get_rssi(struct wlan_hdd_link_info *link_info,
8814 			     int8_t *rssi_value)
8815 {
8816 	int ret = 0, i;
8817 	struct hdd_station_ctx *sta_ctx;
8818 	struct stats_event *rssi_info;
8819 	struct wlan_objmgr_vdev *vdev;
8820 
8821 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
8822 		hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
8823 			cds_get_driver_state());
8824 		/* return a cached value */
8825 		*rssi_value = link_info->rssi;
8826 		return QDF_STATUS_SUCCESS;
8827 	}
8828 
8829 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
8830 	if (!hdd_cm_is_vdev_associated(link_info)) {
8831 		hdd_debug("Not associated!, rssi on disconnect %d",
8832 			  link_info->rssi_on_disconnect);
8833 		*rssi_value = link_info->rssi_on_disconnect;
8834 		return QDF_STATUS_SUCCESS;
8835 	}
8836 
8837 	if (hdd_cm_is_vdev_roaming(link_info)) {
8838 		hdd_debug("Roaming in progress, return cached RSSI");
8839 		*rssi_value = link_info->rssi;
8840 		return QDF_STATUS_SUCCESS;
8841 	}
8842 
8843 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
8844 	if (!vdev) {
8845 		*rssi_value = link_info->rssi;
8846 		return QDF_STATUS_SUCCESS;
8847 	}
8848 
8849 	rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(
8850 			vdev,
8851 			sta_ctx->conn_info.bssid.bytes,
8852 			&ret);
8853 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
8854 	if (ret || !rssi_info) {
8855 		wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8856 		return ret;
8857 	}
8858 
8859 	for (i = 0; i < rssi_info->num_peer_stats; i++) {
8860 		if (!qdf_mem_cmp(rssi_info->peer_stats[i].peer_macaddr,
8861 				 sta_ctx->conn_info.bssid.bytes,
8862 				 QDF_MAC_ADDR_SIZE)) {
8863 			*rssi_value = rssi_info->peer_stats[i].peer_rssi;
8864 			hdd_debug("RSSI = %d", *rssi_value);
8865 			wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8866 			return QDF_STATUS_SUCCESS;
8867 		}
8868 	}
8869 
8870 	wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8871 	hdd_err("bss peer not present in returned result");
8872 	return QDF_STATUS_E_FAULT;
8873 }
8874 
8875 struct snr_priv {
8876 	int8_t snr;
8877 };
8878 
8879 /**
8880  * hdd_get_snr_cb() - "Get SNR" callback function
8881  * @snr: Current SNR of the station
8882  * @context: opaque context originally passed to SME.  HDD always passes
8883  *	a cookie for the request context
8884  *
8885  * Return: None
8886  */
hdd_get_snr_cb(int8_t snr,void * context)8887 static void hdd_get_snr_cb(int8_t snr, void *context)
8888 {
8889 	struct osif_request *request;
8890 	struct snr_priv *priv;
8891 
8892 	request = osif_request_get(context);
8893 	if (!request) {
8894 		hdd_err("Obsolete request");
8895 		return;
8896 	}
8897 
8898 	/* propagate response back to requesting thread */
8899 	priv = osif_request_priv(request);
8900 	priv->snr = snr;
8901 	osif_request_complete(request);
8902 	osif_request_put(request);
8903 }
8904 
wlan_hdd_get_snr(struct wlan_hdd_link_info * link_info,int8_t * snr)8905 QDF_STATUS wlan_hdd_get_snr(struct wlan_hdd_link_info *link_info, int8_t *snr)
8906 {
8907 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
8908 	struct hdd_station_ctx *sta_ctx;
8909 	QDF_STATUS status;
8910 	int ret;
8911 	void *cookie;
8912 	struct osif_request *request;
8913 	struct snr_priv *priv;
8914 	static const struct osif_request_params params = {
8915 		.priv_size = sizeof(*priv),
8916 		.timeout_ms = WLAN_WAIT_TIME_STATS,
8917 	};
8918 
8919 	hdd_enter();
8920 
8921 	ret = wlan_hdd_validate_context(hdd_ctx);
8922 	if (ret)
8923 		return QDF_STATUS_E_FAULT;
8924 
8925 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
8926 
8927 	request = osif_request_alloc(&params);
8928 	if (!request) {
8929 		hdd_err("Request allocation failure");
8930 		return QDF_STATUS_E_FAULT;
8931 	}
8932 	cookie = osif_request_cookie(request);
8933 
8934 	status = sme_get_snr(hdd_ctx->mac_handle, hdd_get_snr_cb,
8935 			     sta_ctx->conn_info.bssid, cookie);
8936 	if (QDF_STATUS_SUCCESS != status) {
8937 		hdd_err("Unable to retrieve RSSI");
8938 		/* we'll returned a cached value below */
8939 	} else {
8940 		/* request was sent -- wait for the response */
8941 		ret = osif_request_wait_for_response(request);
8942 		if (ret) {
8943 			hdd_err("SME timed out while retrieving SNR");
8944 			/* we'll now returned a cached value below */
8945 		} else {
8946 			/* update the adapter with the fresh results */
8947 			priv = osif_request_priv(request);
8948 			link_info->snr = priv->snr;
8949 		}
8950 	}
8951 
8952 	/*
8953 	 * either we never sent a request, we sent a request and
8954 	 * received a response or we sent a request and timed out.
8955 	 * regardless we are done with the request.
8956 	 */
8957 	osif_request_put(request);
8958 
8959 	*snr = link_info->snr;
8960 	hdd_exit();
8961 	return QDF_STATUS_SUCCESS;
8962 }
8963 
8964 struct linkspeed_priv {
8965 	struct link_speed_info linkspeed_info;
8966 };
8967 
8968 static void
hdd_get_link_speed_cb(struct link_speed_info * linkspeed_info,void * context)8969 hdd_get_link_speed_cb(struct link_speed_info *linkspeed_info, void *context)
8970 {
8971 	struct osif_request *request;
8972 	struct linkspeed_priv *priv;
8973 
8974 	if (!linkspeed_info) {
8975 		hdd_err("NULL linkspeed");
8976 		return;
8977 	}
8978 
8979 	request = osif_request_get(context);
8980 	if (!request) {
8981 		hdd_err("Obsolete request");
8982 		return;
8983 	}
8984 
8985 	priv = osif_request_priv(request);
8986 	priv->linkspeed_info = *linkspeed_info;
8987 	osif_request_complete(request);
8988 	osif_request_put(request);
8989 }
8990 
wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info * link_info,struct qdf_mac_addr * mac_address,uint32_t * linkspeed)8991 int wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info *link_info,
8992 				       struct qdf_mac_addr *mac_address,
8993 				       uint32_t *linkspeed)
8994 {
8995 	int ret;
8996 	QDF_STATUS status;
8997 	void *cookie;
8998 	struct link_speed_info *linkspeed_info;
8999 	struct osif_request *request;
9000 	struct linkspeed_priv *priv;
9001 	struct hdd_adapter *adapter = link_info->adapter;
9002 	static const struct osif_request_params params = {
9003 		.priv_size = sizeof(*priv),
9004 		.timeout_ms = WLAN_WAIT_TIME_STATS,
9005 	};
9006 
9007 	if (!linkspeed) {
9008 		hdd_err("NULL argument");
9009 		return -EINVAL;
9010 	}
9011 
9012 	request = osif_request_alloc(&params);
9013 	if (!request) {
9014 		hdd_err("Request allocation failure");
9015 		ret = -ENOMEM;
9016 		goto return_cached_value;
9017 	}
9018 
9019 	cookie = osif_request_cookie(request);
9020 	priv = osif_request_priv(request);
9021 
9022 	linkspeed_info = &priv->linkspeed_info;
9023 	qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address);
9024 	status = sme_get_link_speed(adapter->hdd_ctx->mac_handle,
9025 				    linkspeed_info,
9026 				    cookie, hdd_get_link_speed_cb);
9027 	if (QDF_IS_STATUS_ERROR(status)) {
9028 		hdd_err("Unable to retrieve statistics for link speed");
9029 		ret = qdf_status_to_os_return(status);
9030 		goto cleanup;
9031 	}
9032 	ret = osif_request_wait_for_response(request);
9033 	if (ret) {
9034 		hdd_err("SME timed out while retrieving link speed");
9035 		goto cleanup;
9036 	}
9037 	link_info->estimated_linkspeed = linkspeed_info->estLinkSpeed;
9038 
9039 cleanup:
9040 	/*
9041 	 * either we never sent a request, we sent a request and
9042 	 * received a response or we sent a request and timed out.
9043 	 * regardless we are done with the request.
9044 	 */
9045 	osif_request_put(request);
9046 
9047 return_cached_value:
9048 	*linkspeed = link_info->estimated_linkspeed;
9049 
9050 	return ret;
9051 }
9052 
9053 static uint32_t
wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info * link_info)9054 wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info *link_info)
9055 {
9056 	uint32_t link_speed;
9057 	struct qdf_mac_addr bssid;
9058 
9059 	if (!hdd_cm_is_vdev_associated(link_info)) {
9060 		/* we are not connected so we don't have a classAstats */
9061 		hdd_debug("Not connected");
9062 		return 0;
9063 	}
9064 	qdf_copy_macaddr(&bssid,
9065 			 &link_info->session.station.conn_info.bssid);
9066 
9067 	if (wlan_hdd_get_linkspeed_for_peermac(link_info,
9068 					       &bssid, &link_speed)) {
9069 		hdd_err("Unable to retrieve SME linkspeed");
9070 		return 0;
9071 	}
9072 	hdd_debug("linkspeed = %d", link_speed);
9073 	return link_speed;
9074 }
9075 
9076 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
9077 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
9078 static uint32_t
wlan_hdd_get_mlo_link_speed(struct hdd_adapter * adapter)9079 wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9080 {
9081 	struct hdd_adapter *ml_adapter = NULL;
9082 	struct hdd_adapter *link_adapter = NULL;
9083 	struct hdd_mlo_adapter_info *mlo_adapter_info = NULL;
9084 	uint32_t link_speed = 0;
9085 	uint32_t per_speed;
9086 	uint8_t link_id;
9087 
9088 	ml_adapter = adapter;
9089 	if (hdd_adapter_is_link_adapter(ml_adapter))
9090 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
9091 
9092 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
9093 	for (link_id = 0; link_id < WLAN_MAX_MLD; link_id++) {
9094 		link_adapter = mlo_adapter_info->link_adapter[link_id];
9095 		if (qdf_unlikely(!link_adapter)) {
9096 			hdd_err("link_adapter[%d] is Null", link_id);
9097 			continue;
9098 		}
9099 		per_speed = wlan_hdd_get_per_link_speed(ml_adapter->deflink);
9100 		link_speed += per_speed;
9101 		hdd_debug("Link%d speed=%d, total speed=%d",
9102 			  link_id, per_speed, link_speed);
9103 	}
9104 	return link_speed;
9105 }
9106 #else
9107 static uint32_t
wlan_hdd_get_mlo_link_speed(struct hdd_adapter * adapter)9108 wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9109 {
9110 	struct wlan_hdd_link_info *link_info = NULL;
9111 	uint32_t link_speed = 0;
9112 	uint32_t per_speed;
9113 
9114 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
9115 		per_speed = wlan_hdd_get_per_link_speed(link_info);
9116 		link_speed += per_speed;
9117 		hdd_debug("per_speed=%d, link_speed=%d", per_speed, link_speed);
9118 	}
9119 	return link_speed;
9120 }
9121 #endif
9122 
9123 #else
9124 static uint32_t
wlan_hdd_get_mlo_link_speed(struct hdd_adapter * adapter)9125 wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9126 {
9127 	uint32_t link_speed = wlan_hdd_get_per_link_speed(adapter->deflink);
9128 
9129 	hdd_debug("Not support MLO, linkspeed = %d", link_speed);
9130 	return link_speed;
9131 }
9132 #endif
9133 
wlan_hdd_get_link_speed(struct wlan_hdd_link_info * link_info,uint32_t * link_speed)9134 int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info,
9135 			    uint32_t *link_speed)
9136 {
9137 	struct hdd_adapter *adapter =  link_info->adapter;
9138 	struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
9139 	int ret;
9140 
9141 	ret = wlan_hdd_validate_context(hddctx);
9142 	if (ret)
9143 		return ret;
9144 
9145 	/* Linkspeed is allowed for CLIENT/STA mode */
9146 	if (adapter->device_mode != QDF_P2P_CLIENT_MODE &&
9147 	    adapter->device_mode != QDF_STA_MODE) {
9148 		hdd_err("Link Speed is not allowed in Device mode %s(%d)",
9149 			qdf_opmode_str(adapter->device_mode),
9150 			adapter->device_mode);
9151 		return -ENOTSUPP;
9152 	}
9153 
9154 	if (wlan_hdd_is_mlo_connection(link_info))
9155 		*link_speed = wlan_hdd_get_mlo_link_speed(adapter);
9156 	else
9157 		*link_speed = wlan_hdd_get_per_link_speed(link_info);
9158 
9159 	/* linkspeed in units of 500 kbps */
9160 	*link_speed = (*link_speed) / 500;
9161 	return 0;
9162 }
9163 
wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info * link_info,uint32_t * link_speed,uint8_t * command,uint8_t command_len)9164 int wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info *link_info,
9165 				       uint32_t *link_speed,
9166 				       uint8_t *command,
9167 				       uint8_t command_len)
9168 {
9169 	int ret;
9170 	struct qdf_mac_addr mac_address;
9171 	char macaddr_string[MAC_ADDRESS_STR_LEN + 1];
9172 	uint8_t *value = command;
9173 	struct hdd_adapter *adapter = link_info->adapter;
9174 	struct hdd_station_info *sta_info, *tmp = NULL;
9175 
9176 	value = value + command_len;
9177 	ret = sscanf(value, "%17s", macaddr_string);
9178 
9179 	if (ret != 1)
9180 		return -EINVAL;
9181 
9182 	macaddr_string[MAC_ADDRESS_STR_LEN - 1] = '\0';
9183 	if (!mac_pton(macaddr_string, mac_address.bytes)) {
9184 		hdd_err("String to Hex conversion Failed");
9185 		return -EINVAL;
9186 	}
9187 
9188 	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp,
9189 				  STA_INFO_GET_SOFTAP_LINKSPEED) {
9190 		if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
9191 			if (qdf_is_macaddr_equal(&mac_address,
9192 						 &sta_info->sta_mac)) {
9193 				ret = wlan_hdd_get_linkspeed_for_peermac(
9194 							adapter->deflink,
9195 							&mac_address,
9196 							link_speed);
9197 				hdd_put_sta_info_ref(
9198 						&adapter->sta_info_list,
9199 						&sta_info, true,
9200 						STA_INFO_GET_SOFTAP_LINKSPEED);
9201 				if (tmp)
9202 					hdd_put_sta_info_ref(
9203 						&adapter->sta_info_list,
9204 						&tmp, true,
9205 						STA_INFO_GET_SOFTAP_LINKSPEED);
9206 				break;
9207 			}
9208 		}
9209 		hdd_put_sta_info_ref(&adapter->sta_info_list,
9210 				     &sta_info, true,
9211 				     STA_INFO_GET_SOFTAP_LINKSPEED);
9212 	}
9213 
9214 	if (ret) {
9215 		hdd_err("Unable to retrieve SAP/GO linkspeed");
9216 		return ret;
9217 	}
9218 
9219 	*link_speed = (*link_speed) / 500;
9220 	return 0;
9221 }
9222 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
9223 /**
9224  * wlan_hdd_get_per_peer_stats - get per peer stats if supported by FW
9225  * @link_info: Link info pointer of STA adapter to get stats for
9226  * @peer_stats: Pointer to peer_stats
9227  *
9228  * Return: QDF_STATUS
9229  */
9230 static QDF_STATUS
wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info * link_info,struct cdp_peer_stats * peer_stats)9231 wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info *link_info,
9232 			    struct cdp_peer_stats *peer_stats)
9233 {
9234 	QDF_STATUS status;
9235 	ol_txrx_soc_handle soc;
9236 	uint8_t *peer_mac;
9237 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
9238 
9239 	if (wlan_hdd_validate_context(hdd_ctx)) {
9240 		hdd_err("invalid hdd_ctx");
9241 		return QDF_STATUS_E_FAILURE;
9242 	}
9243 
9244 	soc = cds_get_context(QDF_MODULE_ID_SOC);
9245 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
9246 
9247 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) {
9248 		hdd_debug("mlo per link stats is not supported by FW");
9249 		status = cdp_host_get_peer_stats(soc, link_info->vdev_id,
9250 						 peer_mac, peer_stats);
9251 		return status;
9252 	}
9253 
9254 	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
9255 						 peer_mac, peer_stats,
9256 						 CDP_WILD_PEER_TYPE,
9257 						 WLAN_MAX_MLD);
9258 	return status;
9259 }
9260 
wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info * link_info)9261 void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info)
9262 {
9263 	struct cdp_peer_stats *peer_stats;
9264 	QDF_STATUS status;
9265 	struct wlan_objmgr_psoc *psoc;
9266 	struct hdd_stats *hdd_stats = &link_info->hdd_stats;
9267 
9268 	psoc = link_info->adapter->hdd_ctx->psoc;
9269 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc))
9270 		return;
9271 
9272 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
9273 	if (!peer_stats) {
9274 		hdd_err("Failed to malloc peer_stats");
9275 		return;
9276 	}
9277 
9278 	/*
9279 	 * If failed to get RX rates info, assign an invalid value to the
9280 	 * preamble, used to tell driver to report max rates. The rx_rate
9281 	 * and rx_mcs_index are also assigned with tx_rate and tx_mcs_index
9282 	 * if they are invalid after ASSOC/REASSOC/ROAMING
9283 	 */
9284 	status = wlan_hdd_get_per_peer_stats(link_info, peer_stats);
9285 	if (qdf_unlikely(QDF_IS_STATUS_ERROR(status)) ||
9286 	    qdf_unlikely(peer_stats->rx.last_rx_rate == 0)) {
9287 		hdd_debug("Driver failed to get rx rates, rx mcs=%d, status=%d",
9288 			  hdd_stats->class_a_stat.rx_mcs_index, status);
9289 		hdd_stats->class_a_stat.rx_preamble = INVALID_PREAMBLE;
9290 		if (hdd_stats->class_a_stat.rx_mcs_index == INVALID_MCS_IDX) {
9291 			hdd_stats->class_a_stat.rx_rate =
9292 				hdd_stats->class_a_stat.tx_rate;
9293 			hdd_stats->class_a_stat.rx_mcs_index =
9294 				hdd_stats->class_a_stat.tx_mcs_index;
9295 		}
9296 		qdf_mem_free(peer_stats);
9297 		return;
9298 	}
9299 
9300 	/*
9301 	 * The linkspeed calculated by driver is in kbps so we
9302 	 * convert it in units of 100 kbps expected by userspace
9303 	 */
9304 	hdd_stats->class_a_stat.rx_rate = peer_stats->rx.last_rx_rate / 100;
9305 	hdd_stats->class_a_stat.rx_mcs_index = peer_stats->rx.mcs_info;
9306 	hdd_stats->class_a_stat.rx_nss = peer_stats->rx.nss_info;
9307 	hdd_stats->class_a_stat.rx_gi = peer_stats->rx.gi_info;
9308 	hdd_stats->class_a_stat.rx_preamble = peer_stats->rx.preamble_info;
9309 	hdd_stats->class_a_stat.rx_bw = peer_stats->rx.bw_info;
9310 
9311 	qdf_mem_free(peer_stats);
9312 }
9313 #endif
9314 
wlan_hdd_get_station_stats(struct wlan_hdd_link_info * link_info)9315 int wlan_hdd_get_station_stats(struct wlan_hdd_link_info *link_info)
9316 {
9317 	int ret = 0;
9318 	struct stats_event *stats;
9319 	struct wlan_objmgr_vdev *vdev;
9320 
9321 	if (!get_station_fw_request_needed) {
9322 		hdd_debug("return cached get_station stats");
9323 		return 0;
9324 	}
9325 
9326 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
9327 	if (!vdev)
9328 		return -EINVAL;
9329 
9330 	stats = wlan_cfg80211_mc_cp_stats_get_station_stats(vdev, &ret);
9331 	if (ret || !stats) {
9332 		hdd_err("Invalid stats");
9333 		goto out;
9334 	}
9335 
9336 	if (!stats->vdev_summary_stats || !stats->vdev_chain_rssi ||
9337 	    !stats->peer_adv_stats || !stats->pdev_stats) {
9338 		hdd_err("Invalid:%s%s%s%s",
9339 			stats->vdev_summary_stats ? "" : " vdev_summary_stats",
9340 			stats->vdev_chain_rssi ? "" : " vdev_chain_rssi",
9341 			stats->peer_adv_stats ? "" : " peer_adv_stats",
9342 			stats->pdev_stats ? "" : " pdev_stats");
9343 		ret = -EINVAL;
9344 		goto out;
9345 	}
9346 
9347 	/* update get stats cached time stamp */
9348 	hdd_update_station_stats_cached_timestamp(link_info->adapter);
9349 	hdd_update_link_state_cached_timestamp(link_info->adapter);
9350 	copy_station_stats_to_adapter(link_info, stats);
9351 out:
9352 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
9353 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
9354 	return ret;
9355 }
9356 
9357 #ifdef WLAN_FEATURE_BIG_DATA_STATS
wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info * link_info)9358 int wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info *link_info)
9359 {
9360 	int ret = 0;
9361 	struct big_data_stats_event *big_data_stats;
9362 	struct wlan_objmgr_vdev *vdev;
9363 
9364 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
9365 	if (!vdev)
9366 		return -EINVAL;
9367 
9368 	big_data_stats = wlan_cfg80211_mc_cp_get_big_data_stats(vdev, &ret);
9369 	if (ret || !big_data_stats)
9370 		goto out;
9371 
9372 	copy_station_big_data_stats_to_adapter(link_info, big_data_stats);
9373 out:
9374 	if (big_data_stats)
9375 		wlan_cfg80211_mc_cp_stats_free_big_data_stats_event(
9376 								big_data_stats);
9377 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
9378 	return ret;
9379 }
9380 #endif
9381 
9382 struct temperature_priv {
9383 	int temperature;
9384 };
9385 
9386 /**
9387  * hdd_get_temperature_cb() - "Get Temperature" callback function
9388  * @temperature: measured temperature
9389  * @context: callback context
9390  *
9391  * This function is passed to sme_get_temperature() as the callback
9392  * function to be invoked when the temperature measurement is
9393  * available.
9394  *
9395  * Return: None
9396  */
hdd_get_temperature_cb(int temperature,void * context)9397 static void hdd_get_temperature_cb(int temperature, void *context)
9398 {
9399 	struct osif_request *request;
9400 	struct temperature_priv *priv;
9401 
9402 	hdd_enter();
9403 
9404 	request = osif_request_get(context);
9405 	if (!request) {
9406 		hdd_err("Obsolete request");
9407 		return;
9408 	}
9409 
9410 	priv = osif_request_priv(request);
9411 	priv->temperature = temperature;
9412 	osif_request_complete(request);
9413 	osif_request_put(request);
9414 	hdd_exit();
9415 }
9416 
wlan_hdd_get_temperature(struct hdd_adapter * adapter,int * temperature)9417 int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature)
9418 {
9419 	QDF_STATUS status;
9420 	int ret;
9421 	void *cookie;
9422 	struct osif_request *request;
9423 	struct temperature_priv *priv;
9424 	static const struct osif_request_params params = {
9425 		.priv_size = sizeof(*priv),
9426 		.timeout_ms = WLAN_WAIT_TIME_STATS,
9427 	};
9428 
9429 	hdd_enter();
9430 	if (!adapter) {
9431 		hdd_err("adapter is NULL");
9432 		return -EPERM;
9433 	}
9434 
9435 	if (!wlan_psoc_nif_fw_ext_cap_get(adapter->hdd_ctx->psoc,
9436 					  WLAN_SOC_CEXT_TT_SUPPORT)) {
9437 		hdd_err("WMI_SERVICE_THERM_THROT service from FW is disable");
9438 		return -EINVAL;
9439 	}
9440 
9441 	request = osif_request_alloc(&params);
9442 	if (!request) {
9443 		hdd_err("Request allocation failure");
9444 		return -ENOMEM;
9445 	}
9446 	cookie = osif_request_cookie(request);
9447 	status = sme_get_temperature(adapter->hdd_ctx->mac_handle, cookie,
9448 				     hdd_get_temperature_cb);
9449 	if (QDF_STATUS_SUCCESS != status) {
9450 		hdd_err("Unable to retrieve temperature");
9451 	} else {
9452 		ret = osif_request_wait_for_response(request);
9453 		if (ret) {
9454 			hdd_err("SME timed out while retrieving temperature");
9455 		} else {
9456 			/* update the adapter with the fresh results */
9457 			priv = osif_request_priv(request);
9458 			if (priv->temperature)
9459 				adapter->temperature = priv->temperature;
9460 		}
9461 	}
9462 
9463 	/*
9464 	 * either we never sent a request, we sent a request and
9465 	 * received a response or we sent a request and timed out.
9466 	 * regardless we are done with the request.
9467 	 */
9468 	osif_request_put(request);
9469 
9470 	*temperature = adapter->temperature;
9471 	hdd_exit();
9472 	return 0;
9473 }
9474 
9475 #ifdef TX_MULTIQ_PER_AC
wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context,qdf_netdev_t netdev)9476 void wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context,
9477 				      qdf_netdev_t netdev)
9478 {
9479 	struct hdd_adapter *adapter;
9480 	struct wlan_hdd_link_info *link_info;
9481 	struct hdd_tx_rx_stats *stats;
9482 	uint32_t total_inv_sk_and_skb_hash = 0;
9483 	uint32_t total_qselect_existing_skb_hash = 0;
9484 	uint32_t total_qselect_sk_tx_map = 0;
9485 	uint32_t total_qselect_skb_hash = 0;
9486 	unsigned int i;
9487 
9488 	adapter = WLAN_HDD_GET_PRIV_PTR(netdev);
9489 	if (!adapter) {
9490 		hdd_err("adapter is null");
9491 		return;
9492 	}
9493 
9494 	link_info = adapter->deflink;
9495 
9496 	stats = &link_info->hdd_stats.tx_rx_stats;
9497 
9498 	for (i = 0; i < NUM_CPUS; i++) {
9499 		total_inv_sk_and_skb_hash +=
9500 					  stats->per_cpu[i].inv_sk_and_skb_hash;
9501 		total_qselect_existing_skb_hash +=
9502 				    stats->per_cpu[i].qselect_existing_skb_hash;
9503 		total_qselect_sk_tx_map += stats->per_cpu[i].qselect_sk_tx_map;
9504 		total_qselect_skb_hash +=
9505 					stats->per_cpu[i].qselect_skb_hash_calc;
9506 	}
9507 
9508 	hdd_debug("TX_MULTIQ: INV %u skb_hash %u sk_tx_map %u skb_hash_calc %u",
9509 		  total_inv_sk_and_skb_hash, total_qselect_existing_skb_hash,
9510 		  total_qselect_sk_tx_map, total_qselect_skb_hash);
9511 }
9512 #endif
9513 
9514 #ifdef QCA_SUPPORT_CP_STATS
9515 /**
9516  * hdd_lost_link_cp_stats_info_cb() - callback function to get lost
9517  * link information
9518  * @stats_ev: Stats event pointer
9519  * FW sends vdev stats on vdev down, this callback is registered
9520  * with cp_stats component to get the last available vdev stats
9521  * From the FW.
9522  *
9523  * Return: None
9524  */
9525 
hdd_lost_link_cp_stats_info_cb(void * stats_ev)9526 static void hdd_lost_link_cp_stats_info_cb(void *stats_ev)
9527 {
9528 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
9529 	struct stats_event *ev = stats_ev;
9530 	uint8_t i, vdev_id;
9531 	int8_t rssi;
9532 	struct hdd_station_ctx *sta_ctx;
9533 	struct wlan_hdd_link_info *link_info;
9534 	struct qdf_mac_addr *mac_addr;
9535 
9536 	if (wlan_hdd_validate_context(hdd_ctx))
9537 		return;
9538 
9539 	for (i = 0; i < ev->num_summary_stats; i++) {
9540 		vdev_id = ev->vdev_summary_stats[i].vdev_id;
9541 		link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
9542 		if (!link_info) {
9543 			hdd_debug("invalid vdev %d", vdev_id);
9544 			continue;
9545 		}
9546 
9547 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
9548 
9549 		rssi = ev->vdev_summary_stats[i].stats.rssi;
9550 		if (rssi == 0) {
9551 			hdd_debug_rl("Invalid RSSI value sent by FW");
9552 			return;
9553 		}
9554 		link_info->rssi_on_disconnect = rssi;
9555 		sta_ctx->cache_conn_info.signal = rssi;
9556 
9557 		mac_addr = hdd_adapter_get_link_mac_addr(link_info);
9558 		if (!mac_addr)
9559 			return;
9560 
9561 		hdd_debug("rssi %d for " QDF_MAC_ADDR_FMT,
9562 			  link_info->rssi_on_disconnect,
9563 			  QDF_MAC_ADDR_REF(&mac_addr->bytes[0]));
9564 
9565 	}
9566 }
9567 
wlan_hdd_register_cp_stats_cb(struct hdd_context * hdd_ctx)9568 void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx)
9569 {
9570 	ucfg_mc_cp_stats_register_lost_link_info_cb(
9571 					hdd_ctx->psoc,
9572 					hdd_lost_link_cp_stats_info_cb);
9573 }
9574 #endif
9575 
9576 #if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_ROAM_INFO_STATS)
9577 #define ROAM_CACHED_STATS_MAX QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_MAX
9578 
9579 #define EVENTS_CONFIGURE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE
9580 #define SUSPEND_STATE    QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE
9581 
9582 #define ROAM_STATS_ROAM_TRIGGER_TIMESTAMP \
9583 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_TRIGGER_TIMESTAMP
9584 #define ROAM_STATS_TRIGGER_REASON \
9585 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TRIGGER_REASON
9586 #define ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT \
9587 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT
9588 #define ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT \
9589 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT
9590 #define ROAM_STATS_FINAL_BMISS_CNT \
9591 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FINAL_BMISS_CNT
9592 #define ROAM_STATS_CONSECUTIVE_BMISS_CNT \
9593 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONSECUTIVE_BMISS_CNT
9594 #define ROAM_STATS_BMISS_QOS_NULL_SUCCESS \
9595 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BMISS_QOS_NULL_SUCCESS
9596 #define ROAM_STATS_POOR_RSSI_CURRENT_RSSI \
9597 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_CURRENT_RSSI
9598 #define ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD \
9599 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD
9600 #define ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS \
9601 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS
9602 #define ROAM_STATS_BETTER_RSSI_CURRENT_RSSI \
9603 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_CURRENT_RSSI
9604 #define ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD \
9605 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD
9606 #define ROAM_STATS_CONGESTION_RX_TPUT \
9607 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_RX_TPUT
9608 #define ROAM_STATS_CONGESTION_TX_TPUT \
9609 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_TX_TPUT
9610 #define ROAM_STATS_CONGESTION_ROAMABLE_CNT \
9611 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_ROAMABLE_CNT
9612 #define ROAM_STATS_USER_TRIGGER_INVOKE_REASON \
9613 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_USER_TRIGGER_INVOKE_REASON
9614 #define ROAM_STATS_BTM_REQUEST_MODE \
9615 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQUEST_MODE
9616 #define ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME \
9617 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME
9618 #define ROAM_STATS_BTM_VALID_INTERNAL \
9619 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_VALID_INTERNAL
9620 #define ROAM_STATS_BTM_CANDIDATE_LIST_CNT \
9621 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_CANDIDATE_LIST_CNT
9622 #define ROAM_STATS_BTM_RESPONSE_STATUS_CODE \
9623 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_RESPONSE_STATUS_CODE
9624 #define ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT \
9625 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT
9626 #define ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT \
9627 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT
9628 #define ROAM_STATS_BTM_REQ_DIALOG_TOKEN \
9629 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQ_DIALOG_TOKEN
9630 #define ROAM_STATS_BSS_CU_LOAD \
9631 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BSS_CU_LOAD
9632 #define ROAM_STATS_DISCONNECTION_TYPE \
9633 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_TYPE
9634 #define ROAM_STATS_DISCONNECTION_REASON \
9635 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_REASON
9636 #define ROAM_STATS_PERIODIC_TIMER_MS \
9637 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PERIODIC_TIMER_MS
9638 #define ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI \
9639 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI
9640 #define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI \
9641 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI
9642 #define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH \
9643 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_THRESH
9644 #define ROAM_STATS_TX_FAILURES_THRESHOLD \
9645 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_THRESHOLD
9646 #define ROAM_STATS_TX_FAILURES_REASON \
9647 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_REASON
9648 #define ROAM_STATS_ABORT_REASON \
9649 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON
9650 #define ROAM_STATS_DATA_RSSI \
9651 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI
9652 #define ROAM_STATS_DATA_RSSI_THRESHOLD \
9653 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI_THRESHOLD
9654 #define ROAM_STATS_DATA_RX_LINKSPEED_STATUS \
9655 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RX_LINKSPEED_STATUS
9656 #define ROAM_STATS_SCAN_TYPE \
9657 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE
9658 #define ROAM_STATS_ROAM_STATUS \
9659 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS
9660 #define ROAM_STATS_FAIL_REASON \
9661 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FAIL_REASON
9662 #define ROAM_STATS_SCAN_CHAN_INFO \
9663 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO
9664 #define ROAM_STATS_TOTAL_SCAN_TIME \
9665 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TOTAL_SCAN_TIME
9666 #define ROAM_STATS_FRAME_INFO  \
9667 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO
9668 #define ROAM_STATS_SCAN_CHANNEL_FREQ \
9669 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHANNEL_FREQ
9670 #define ROAM_STATS_SCAN_DWELL_TYPE \
9671 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE
9672 #define ROAM_STATS_MAX_DWELL_TIME \
9673 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_MAX_DWELL_TIME
9674 #define ROAM_STATS_FRAME_SUBTYPE \
9675 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_SUBTYPE
9676 #define ROAM_STATS_FRAME_STATUS \
9677 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_STATUS
9678 #define ROAM_STATS_FRAME_TIMESTAMP \
9679 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_TIMESTAMP
9680 #define ROAM_STATS_EVENT_INDEX \
9681 	QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS_INDEX
9682 
9683 static enum qca_roam_reason
hdd_convert_roam_trigger_reason(enum roam_trigger_reason reason)9684 hdd_convert_roam_trigger_reason(enum roam_trigger_reason reason)
9685 {
9686 	switch (reason) {
9687 	case ROAM_TRIGGER_REASON_NONE:
9688 		return QCA_ROAM_REASON_UNKNOWN;
9689 	case ROAM_TRIGGER_REASON_PER:
9690 		return QCA_ROAM_REASON_PER;
9691 	case ROAM_TRIGGER_REASON_BMISS:
9692 		return QCA_ROAM_REASON_BEACON_MISS;
9693 	case ROAM_TRIGGER_REASON_LOW_RSSI:
9694 		return QCA_ROAM_REASON_POOR_RSSI;
9695 	case ROAM_TRIGGER_REASON_HIGH_RSSI:
9696 		return QCA_ROAM_REASON_BETTER_RSSI;
9697 	case ROAM_TRIGGER_REASON_PERIODIC:
9698 		return QCA_ROAM_REASON_PERIODIC_TIMER;
9699 	case ROAM_TRIGGER_REASON_DENSE:
9700 		return QCA_ROAM_REASON_CONGESTION;
9701 	case ROAM_TRIGGER_REASON_BACKGROUND:
9702 		return QCA_ROAM_REASON_BACKGROUND_SCAN;
9703 	case ROAM_TRIGGER_REASON_FORCED:
9704 		return QCA_ROAM_REASON_USER_TRIGGER;
9705 	case ROAM_TRIGGER_REASON_BTM:
9706 		return QCA_ROAM_REASON_BTM;
9707 	case ROAM_TRIGGER_REASON_BSS_LOAD:
9708 		return QCA_ROAM_REASON_BSS_LOAD;
9709 	case ROAM_TRIGGER_REASON_DEAUTH:
9710 		return QCA_ROAM_REASON_DISCONNECTION;
9711 	case ROAM_TRIGGER_REASON_STA_KICKOUT:
9712 		return QCA_ROAM_REASON_STA_KICKOUT;
9713 	default:
9714 		hdd_err("Invalid invoke reason received: %d", reason);
9715 		break;
9716 	}
9717 
9718 	return QCA_ROAM_REASON_UNKNOWN;
9719 }
9720 
9721 static enum qca_wlan_roam_stats_invoke_reason
hdd_convert_roam_invoke_reason(enum roam_invoke_reason invoke)9722 hdd_convert_roam_invoke_reason(enum roam_invoke_reason invoke)
9723 {
9724 	switch (invoke) {
9725 	case WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED:
9726 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED;
9727 	case WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE:
9728 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE;
9729 	case WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE:
9730 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE;
9731 	default:
9732 		hdd_err("Invalid invoke reason received: %d", invoke);
9733 		break;
9734 	}
9735 
9736 	return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED;
9737 }
9738 
9739 static enum qca_wlan_roam_stats_tx_failures_reason
hdd_convert_roam_tx_failures_reason(enum roam_tx_failures_reason tx_failures)9740 hdd_convert_roam_tx_failures_reason(enum roam_tx_failures_reason tx_failures)
9741 {
9742 	switch (tx_failures) {
9743 	case WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED:
9744 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED;
9745 	case WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY:
9746 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY;
9747 	case WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY:
9748 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY;
9749 	case WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT:
9750 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT;
9751 	case WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT:
9752 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT;
9753 	case WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT:
9754 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT;
9755 	case WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT:
9756 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT;
9757 	default:
9758 		hdd_err("Invalid tx_failures reason received: %d", tx_failures);
9759 		break;
9760 	}
9761 
9762 	return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED;
9763 }
9764 
9765 static enum qca_wlan_roam_stats_abort_reason
hdd_convert_roam_abort_reason(enum roam_abort_reason abort)9766 hdd_convert_roam_abort_reason(enum roam_abort_reason abort)
9767 {
9768 	switch (abort) {
9769 	case WLAN_ROAM_STATS_ABORT_UNSPECIFIED:
9770 		return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED;
9771 	case WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH:
9772 		return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH;
9773 	case WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD:
9774 		return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD;
9775 	case WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH:
9776 		return QCA_WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH;
9777 	case WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD:
9778 		return QCA_WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD;
9779 	default:
9780 		hdd_err("Invalid abort reason received: %d", abort);
9781 		break;
9782 	}
9783 
9784 	return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED;
9785 }
9786 
9787 static enum qca_wlan_roam_stats_scan_type
hdd_convert_roam_scan_type(enum roam_stats_scan_type type)9788 hdd_convert_roam_scan_type(enum roam_stats_scan_type              type)
9789 {
9790 	switch (type) {
9791 	case ROAM_STATS_SCAN_TYPE_PARTIAL:
9792 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL;
9793 	case ROAM_STATS_SCAN_TYPE_FULL:
9794 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL;
9795 	case ROAM_STATS_SCAN_TYPE_NO_SCAN:
9796 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN;
9797 	case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ:
9798 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ;
9799 	case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ:
9800 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ;
9801 	default:
9802 		hdd_err("Invalid roam scan type received: %d", type);
9803 		break;
9804 	}
9805 
9806 	return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL;
9807 }
9808 
9809 static enum qca_wlan_roam_stats_scan_dwell_type
hdd_convert_roam_chn_dwell_type(enum roam_scan_dwell_type type)9810 hdd_convert_roam_chn_dwell_type(enum roam_scan_dwell_type type)
9811 {
9812 	switch (type) {
9813 	case WLAN_ROAM_DWELL_TYPE_UNSPECIFIED:
9814 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED;
9815 	case WLAN_ROAM_DWELL_ACTIVE_TYPE:
9816 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_ACTIVE;
9817 	case WLAN_ROAM_DWELL_PASSIVE_TYPE:
9818 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_PASSIVE;
9819 	default:
9820 		hdd_err("Invalid abort reason received: %d", type);
9821 		break;
9822 	}
9823 
9824 	return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED;
9825 }
9826 
9827 static enum qca_wlan_roam_stats_frame_subtype
hdd_convert_roam_frame_type(enum eroam_frame_subtype type)9828 hdd_convert_roam_frame_type(enum eroam_frame_subtype type)
9829 {
9830 	switch (type) {
9831 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ:
9832 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
9833 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP:
9834 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP;
9835 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ:
9836 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ;
9837 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP:
9838 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP;
9839 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1:
9840 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1;
9841 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2:
9842 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2;
9843 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3:
9844 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3;
9845 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4:
9846 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4;
9847 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1:
9848 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1;
9849 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2:
9850 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2;
9851 	default:
9852 		hdd_err_rl("Invalid roam frame type received: %d", type);
9853 		break;
9854 	}
9855 
9856 	return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
9857 };
9858 
9859 static enum qca_wlan_roam_stats_frame_status
hdd_convert_roam_frame_status(enum eroam_frame_status status)9860 hdd_convert_roam_frame_status(enum eroam_frame_status status)
9861 {
9862 	switch (status) {
9863 	case WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS:
9864 		return QCA_WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS;
9865 	case WLAN_ROAM_STATS_FRAME_STATUS_FAIL:
9866 		return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL;
9867 	default:
9868 		hdd_err("Invalid roam frame status received: %d", status);
9869 		break;
9870 	}
9871 
9872 	return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL;
9873 };
9874 
9875 static enum qca_vendor_roam_fail_reasons
hdd_convert_roam_failures_reason(enum wlan_roam_failure_reason_code fail)9876 hdd_convert_roam_failures_reason(enum wlan_roam_failure_reason_code fail)
9877 {
9878 	switch (fail) {
9879 	case ROAM_FAIL_REASON_NO_SCAN_START:
9880 		return QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED;
9881 	case ROAM_FAIL_REASON_NO_AP_FOUND:
9882 		return QCA_ROAM_FAIL_REASON_NO_AP_FOUND;
9883 	case ROAM_FAIL_REASON_NO_CAND_AP_FOUND:
9884 		return QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND;
9885 	case ROAM_FAIL_REASON_HOST:
9886 		return QCA_ROAM_FAIL_REASON_HOST;
9887 	case ROAM_FAIL_REASON_AUTH_SEND:
9888 		return QCA_ROAM_FAIL_REASON_AUTH_SEND;
9889 	case ROAM_FAIL_REASON_NO_AUTH_RESP:
9890 		return QCA_ROAM_FAIL_REASON_NO_AUTH_RESP;
9891 	case ROAM_FAIL_REASON_AUTH_RECV:
9892 		return QCA_ROAM_FAIL_REASON_AUTH_RECV;
9893 	case ROAM_FAIL_REASON_REASSOC_SEND:
9894 		return QCA_ROAM_FAIL_REASON_REASSOC_SEND;
9895 	case ROAM_FAIL_REASON_REASSOC_RECV:
9896 		return QCA_ROAM_FAIL_REASON_REASSOC_RECV;
9897 	case ROAM_FAIL_REASON_NO_REASSOC_RESP:
9898 		return QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP;
9899 	case ROAM_FAIL_REASON_EAPOL_TIMEOUT:
9900 		return QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT;
9901 	case ROAM_FAIL_REASON_SCAN_START:
9902 		return QCA_ROAM_FAIL_REASON_SCAN_FAIL;
9903 	case ROAM_FAIL_REASON_AUTH_NO_ACK:
9904 		return QCA_ROAM_FAIL_REASON_AUTH_NO_ACK;
9905 	case ROAM_FAIL_REASON_AUTH_INTERNAL_DROP:
9906 		return QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP;
9907 	case ROAM_FAIL_REASON_REASSOC_NO_ACK:
9908 		return QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK;
9909 	case ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP:
9910 		return QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP;
9911 	case ROAM_FAIL_REASON_EAPOL_M2_SEND:
9912 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND;
9913 	case ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP:
9914 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP;
9915 	case ROAM_FAIL_REASON_EAPOL_M2_NO_ACK:
9916 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK;
9917 	case ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT:
9918 		return QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT;
9919 	case ROAM_FAIL_REASON_EAPOL_M4_SEND:
9920 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND;
9921 	case ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP:
9922 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP;
9923 	case ROAM_FAIL_REASON_EAPOL_M4_NO_ACK:
9924 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK;
9925 	case ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS:
9926 		return QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS;
9927 	case ROAM_FAIL_REASON_DISCONNECT:
9928 		return QCA_ROAM_FAIL_REASON_DISCONNECT;
9929 	case ROAM_FAIL_REASON_SYNC:
9930 		return QCA_ROAM_FAIL_REASON_RESUME_ABORT;
9931 	case ROAM_FAIL_REASON_SAE_INVALID_PMKID:
9932 		return QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID;
9933 	case ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT:
9934 		return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT;
9935 	case ROAM_FAIL_REASON_SAE_PREAUTH_FAIL:
9936 		return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL;
9937 	case ROAM_FAIL_REASON_CURR_AP_STILL_OK:
9938 		return QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK;
9939 	case ROAM_FAIL_REASON_MLME:
9940 	case ROAM_FAIL_REASON_INTERNAL_ABORT:
9941 	case ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO:
9942 	case ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT:
9943 	case ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT:
9944 	case ROAM_FAIL_REASON_SCAN_CANCEL:
9945 	case ROAM_FAIL_REASON_SCREEN_ACTIVITY:
9946 	case ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN:
9947 	case ROAM_FAIL_REASON_UNKNOWN:
9948 		hdd_err("Invalid roam failures reason");
9949 		break;
9950 	}
9951 
9952 	return QCA_ROAM_FAIL_REASON_NONE;
9953 }
9954 
9955 /**
9956  * hdd_get_roam_stats_individual_record_len() - calculates the required length
9957  * of an individual record of roaming stats
9958  *
9959  * @roam_info: pointer to roam info
9960  * @index:     index of roam info cached in driver
9961  *
9962  * Return: required length of an individual record of roaming stats
9963  */
9964 static uint32_t
hdd_get_roam_stats_individual_record_len(struct enhance_roam_info * roam_info,uint32_t index)9965 hdd_get_roam_stats_individual_record_len(struct enhance_roam_info *roam_info,
9966 					 uint32_t index)
9967 {
9968 	struct enhance_roam_info *info;
9969 	enum qca_roam_reason vendor_trigger_reason;
9970 	uint32_t len, i;
9971 
9972 	if (!roam_info) {
9973 		hdd_err("invalid param");
9974 		return 0;
9975 	}
9976 
9977 	info  = &roam_info[index];
9978 	vendor_trigger_reason =
9979 		hdd_convert_roam_trigger_reason(info->trigger.trigger_reason);
9980 
9981 	len = 0;
9982 	/* ROAM_STATS_ROAM_TRIGGER_TIMESTAMP */
9983 	len += nla_total_size_64bit(sizeof(uint64_t));
9984 	/* ROAM_STATS_TRIGGER_REASON */
9985 	len += nla_total_size(sizeof(uint32_t));
9986 
9987 	switch (vendor_trigger_reason) {
9988 	case QCA_ROAM_REASON_PER:
9989 		/* ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT */
9990 		len += nla_total_size(sizeof(uint8_t));
9991 		/* ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT */
9992 		len += nla_total_size(sizeof(uint8_t));
9993 		break;
9994 	case QCA_ROAM_REASON_BEACON_MISS:
9995 		/* ROAM_STATS_FINAL_BMISS_CNT */
9996 		len += nla_total_size(sizeof(uint32_t));
9997 		/* ROAM_STATS_CONSECUTIVE_BMISS_CNT */
9998 		len += nla_total_size(sizeof(uint32_t));
9999 		/* ROAM_STATS_BMISS_QOS_NULL_SUCCESS */
10000 		len += nla_total_size(sizeof(uint8_t));
10001 		break;
10002 	case QCA_ROAM_REASON_POOR_RSSI:
10003 		/* ROAM_STATS_POOR_RSSI_CURRENT_RSSI */
10004 		len += nla_total_size(sizeof(int8_t));
10005 		/* ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD */
10006 		len += nla_total_size(sizeof(int8_t));
10007 		/* ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS */
10008 		len += nla_total_size(sizeof(uint8_t));
10009 		break;
10010 	case QCA_ROAM_REASON_BETTER_RSSI:
10011 		/* ROAM_STATS_BETTER_RSSI_CURRENT_RSSI */
10012 		len += nla_total_size(sizeof(int8_t));
10013 		/* ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD */
10014 		len += nla_total_size(sizeof(int8_t));
10015 		break;
10016 	case QCA_ROAM_REASON_PERIODIC_TIMER:
10017 		/* ROAM_STATS_PERIODIC_TIMER_MS */
10018 		len += nla_total_size(sizeof(uint32_t));
10019 		break;
10020 	case QCA_ROAM_REASON_CONGESTION:
10021 		/* ROAM_STATS_CONGESTION_RX_TPUT */
10022 		len += nla_total_size(sizeof(uint32_t));
10023 		/* ROAM_STATS_CONGESTION_TX_TPUT */
10024 		len += nla_total_size(sizeof(uint32_t));
10025 		/* ROAM_STATS_CONGESTION_ROAMABLE_CNT */
10026 		len += nla_total_size(sizeof(uint8_t));
10027 		break;
10028 	case QCA_ROAM_REASON_BACKGROUND_SCAN:
10029 		/* ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI */
10030 		len += nla_total_size(sizeof(int8_t));
10031 		/* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI */
10032 		len += nla_total_size(sizeof(int8_t));
10033 		/* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH */
10034 		len += nla_total_size(sizeof(int8_t));
10035 		break;
10036 	case QCA_ROAM_REASON_USER_TRIGGER:
10037 		/* ROAM_STATS_USER_TRIGGER_INVOKE_REASON */
10038 		len += nla_total_size(sizeof(uint8_t));
10039 		break;
10040 	case QCA_ROAM_REASON_BTM:
10041 		/* ROAM_STATS_BTM_REQUEST_MODE */
10042 		len += nla_total_size(sizeof(uint8_t));
10043 		/* ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME */
10044 		len += nla_total_size(sizeof(uint32_t));
10045 		/* ROAM_STATS_BTM_VALID_INTERNAL */
10046 		len += nla_total_size(sizeof(uint32_t));
10047 		/* ROAM_STATS_BTM_CANDIDATE_LIST_CNT */
10048 		len += nla_total_size(sizeof(uint8_t));
10049 		/* ROAM_STATS_BTM_RESPONSE_STATUS_CODE */
10050 		len += nla_total_size(sizeof(uint8_t));
10051 		/* ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT */
10052 		len += nla_total_size(sizeof(uint32_t));
10053 		/* ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT */
10054 		len += nla_total_size(sizeof(uint32_t));
10055 		/* ROAM_STATS_BTM_REQ_DIALOG_TOKEN */
10056 		len += nla_total_size(sizeof(uint8_t));
10057 		break;
10058 	case QCA_ROAM_REASON_BSS_LOAD:
10059 		/* ROAM_STATS_BSS_CU_LOAD */
10060 		len += nla_total_size(sizeof(uint8_t));
10061 		break;
10062 	case QCA_ROAM_REASON_DISCONNECTION:
10063 		/* ROAM_STATS_DISCONNECTION_TYPE */
10064 		len += nla_total_size(sizeof(uint8_t));
10065 		/* ROAM_STATS_DISCONNECTION_REASON */
10066 		len += nla_total_size(sizeof(uint16_t));
10067 		break;
10068 	case QCA_ROAM_REASON_STA_KICKOUT:
10069 		/* ROAM_STATS_TX_FAILURES_THRESHOLD */
10070 		len += nla_total_size(sizeof(uint32_t));
10071 		/* ROAM_STATS_TX_FAILURES_REASON */
10072 		len += nla_total_size(sizeof(uint8_t));
10073 		break;
10074 	default:
10075 		break;
10076 	}
10077 
10078 	/* ROAM_STATS_SCAN_TYPE */
10079 	len += nla_total_size(sizeof(uint8_t));
10080 	/* ROAM_STATS_ROAM_STATUS */
10081 	len += nla_total_size(sizeof(uint8_t));
10082 
10083 	if (info->trigger.roam_status) {
10084 		/* ROAM_STATS_FAIL_REASON */
10085 		len += nla_total_size(sizeof(uint8_t));
10086 		if (info->trigger.abort.abort_reason_code) {
10087 			/* ROAM_STATS_ABORT_REASON */
10088 			len += nla_total_size(sizeof(uint8_t));
10089 			/* ROAM_STATS_DATA_RSSI */
10090 			len += nla_total_size(sizeof(int8_t));
10091 			/* ROAM_STATS_DATA_RSSI_THRESHOLD */
10092 			len += nla_total_size(sizeof(int8_t));
10093 			/* ROAM_STATS_DATA_RX_LINKSPEED_STATUS */
10094 			len += nla_total_size(sizeof(uint8_t));
10095 		}
10096 	}
10097 
10098 	/* ROAM_STATS_SCAN_CHAN_INFO */
10099 	len += nla_total_size(0);
10100 	for (i = 0; i < info->scan.num_channels; i++) {
10101 		/* nest attribute */
10102 		len += nla_total_size(0);
10103 		/* ROAM_STATS_SCAN_CHANNEL_FREQ */
10104 		len += nla_total_size(sizeof(uint32_t));
10105 		/* ROAM_STATS_SCAN_DWELL_TYPE */
10106 		len += nla_total_size(sizeof(uint32_t));
10107 		/* ROAM_STATS_MAX_DWELL_TIME */
10108 		len += nla_total_size(sizeof(uint32_t));
10109 	}
10110 
10111 	/* ROAM_STATS_TOTAL_SCAN_TIME */
10112 	len += nla_total_size(sizeof(uint32_t));
10113 
10114 	/* ROAM_STATS_FRAME_INFO */
10115 	len += nla_total_size(0);
10116 	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
10117 		/* nest attribute */
10118 		len += nla_total_size(0);
10119 		/* ROAM_STATS_FRAME_SUBTYPE */
10120 		len += nla_total_size(sizeof(uint8_t));
10121 		/* ROAM_STATS_FRAME_STATUS */
10122 		len += nla_total_size(sizeof(uint8_t));
10123 		/* ROAM_STATS_FRAME_TIMESTAMP */
10124 		len += nla_total_size_64bit(sizeof(uint64_t));
10125 	}
10126 
10127 	return len;
10128 }
10129 
10130 /**
10131  * hdd_get_roam_stats_info_len() - calculate the length required by skb
10132  * @roam_info: pointer to roam info
10133  * @roam_cache_num: roam cache number
10134  *
10135  * Calculate the required length to send roam stats to upper layer
10136  *
10137  * Return: required len
10138  */
10139 static uint32_t
hdd_get_roam_stats_info_len(struct enhance_roam_info * roam_info,uint8_t roam_cache_num)10140 hdd_get_roam_stats_info_len(struct enhance_roam_info *roam_info,
10141 			    uint8_t roam_cache_num)
10142 {
10143 	uint32_t len, i;
10144 
10145 	len = 0;
10146 	/* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */
10147 	len += nla_total_size(0);
10148 	for (i = 0; i < roam_cache_num; i++) {
10149 		/* nest attribute */
10150 		len += nla_total_size(0);
10151 		len += hdd_get_roam_stats_individual_record_len(roam_info, i);
10152 	}
10153 
10154 	return len;
10155 }
10156 
10157 /**
10158  * hdd_nla_put_roam_stats_info() - put roam statistics info attribute
10159  * values to userspace
10160  *
10161  * @skb:       pointer to sk buff
10162  * @roam_info: pointer to roam info
10163  * @index:     index of roam info cached in driver
10164  *
10165  * Return: 0 if success else error status
10166  */
hdd_nla_put_roam_stats_info(struct sk_buff * skb,struct enhance_roam_info * roam_info,uint32_t index)10167 static int hdd_nla_put_roam_stats_info(struct sk_buff *skb,
10168 				       struct enhance_roam_info *roam_info,
10169 				       uint32_t index)
10170 {
10171 	struct nlattr *roam_chn_info, *roam_chn;
10172 	struct nlattr *roam_frame_info, *roam_frame;
10173 	struct enhance_roam_info *info;
10174 	enum roam_invoke_reason driver_invoke_reason;
10175 	enum qca_wlan_roam_stats_invoke_reason vendor_invoke_reason;
10176 	enum roam_tx_failures_reason driver_tx_failures_reason;
10177 	enum qca_wlan_roam_stats_tx_failures_reason vendor_tx_failures_reason;
10178 	enum roam_abort_reason driver_abort_reason;
10179 	enum qca_wlan_roam_stats_abort_reason vendor_abort_reason;
10180 	enum qca_wlan_roam_stats_scan_type vendor_scan_type;
10181 	enum roam_scan_dwell_type driver_dwell_type;
10182 	enum qca_wlan_roam_stats_scan_dwell_type vendor_dwell_type;
10183 	enum eroam_frame_subtype driver_frame_type;
10184 	enum qca_wlan_roam_stats_frame_subtype vendor_frame_type;
10185 	enum eroam_frame_status driver_frame_status;
10186 	enum qca_wlan_roam_stats_frame_status vendor_frame_status;
10187 	enum qca_roam_reason vendor_trigger_reason;
10188 	enum qca_vendor_roam_fail_reasons vendor_fail_reason;
10189 	uint32_t i;
10190 	int ret;
10191 
10192 	if (!roam_info) {
10193 		hdd_err("invalid param");
10194 		return -EINVAL;
10195 	}
10196 	info  = &roam_info[index];
10197 
10198 	vendor_trigger_reason =
10199 		hdd_convert_roam_trigger_reason(info->trigger.trigger_reason);
10200 
10201 	if (wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_ROAM_TRIGGER_TIMESTAMP,
10202 				      info->trigger.timestamp)) {
10203 		hdd_err("timestamp put fail");
10204 		return -EINVAL;
10205 	}
10206 
10207 	if (nla_put_u32(skb, ROAM_STATS_TRIGGER_REASON, vendor_trigger_reason)) {
10208 		hdd_err(" put fail");
10209 		return -EINVAL;
10210 	}
10211 
10212 	switch (vendor_trigger_reason) {
10213 	case QCA_ROAM_REASON_PER:
10214 		if (nla_put_u8(skb,  ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT,
10215 			       info->trigger.condition.roam_per.rx_rate_thresh_percent)) {
10216 			hdd_err("roam_per.rx_rate_thresh_percent put fail");
10217 			return -EINVAL;
10218 		}
10219 		if (nla_put_u8(skb,  ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT,
10220 			       info->trigger.condition.roam_per.tx_rate_thresh_percent)) {
10221 			hdd_err("roam_per.rx_rate_thresh_percent put fail");
10222 			return -EINVAL;
10223 		}
10224 		break;
10225 	case QCA_ROAM_REASON_BEACON_MISS:
10226 		if (nla_put_u32(skb, ROAM_STATS_FINAL_BMISS_CNT,
10227 				info->trigger.condition.roam_bmiss.final_bmiss_cnt)) {
10228 			hdd_err("roam_bmiss.final_bmiss_cnt put fail");
10229 			return -EINVAL;
10230 		}
10231 		if (nla_put_u32(skb, ROAM_STATS_CONSECUTIVE_BMISS_CNT,
10232 				info->trigger.condition.roam_bmiss.consecutive_bmiss_cnt)) {
10233 			hdd_err("roam_bmiss.consecutive_bmiss_cnt put fail");
10234 			return -EINVAL;
10235 		}
10236 		if (nla_put_u8(skb, ROAM_STATS_BMISS_QOS_NULL_SUCCESS,
10237 			       info->trigger.condition.roam_bmiss.qos_null_success)) {
10238 			hdd_err("roam_bmiss.qos_null_success put fail");
10239 			return -EINVAL;
10240 		}
10241 		break;
10242 	case QCA_ROAM_REASON_POOR_RSSI:
10243 		if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_CURRENT_RSSI,
10244 			       info->trigger.condition.roam_poor_rssi.current_rssi)) {
10245 			hdd_err("roam_poor_rssi.current_rssi put fail");
10246 			return -EINVAL;
10247 		}
10248 		if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD,
10249 			       info->trigger.condition.roam_poor_rssi.roam_rssi_threshold)) {
10250 			hdd_err("roam_poor_rssi.roam_rssi_threshold put fail");
10251 			return -EINVAL;
10252 		}
10253 		if (nla_put_u8(skb, ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS,
10254 			       info->trigger.condition.roam_poor_rssi.rx_linkspeed_status)) {
10255 			hdd_err("roam_poor_rssi.rx_linkspeed_status put fail");
10256 			return -EINVAL;
10257 		}
10258 		break;
10259 	case QCA_ROAM_REASON_BETTER_RSSI:
10260 		if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_CURRENT_RSSI,
10261 			       info->trigger.condition.roam_better_rssi.current_rssi)) {
10262 			hdd_err("roam_better_rssi.current_rssi put fail");
10263 			return -EINVAL;
10264 		}
10265 		if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD,
10266 			       info->trigger.condition.roam_better_rssi.hi_rssi_threshold)) {
10267 			hdd_err("roam_better_rssi.hi_rssi_threshold put fail");
10268 			return -EINVAL;
10269 		}
10270 		break;
10271 	case QCA_ROAM_REASON_PERIODIC_TIMER:
10272 		if (nla_put_u32(skb, ROAM_STATS_PERIODIC_TIMER_MS,
10273 				info->trigger.condition.roam_periodic.periodic_timer_ms)) {
10274 			hdd_err("roam_periodic.periodic_timer_ms put fail");
10275 			return -EINVAL;
10276 		}
10277 		break;
10278 	case QCA_ROAM_REASON_CONGESTION:
10279 		if (nla_put_u32(skb, ROAM_STATS_CONGESTION_RX_TPUT,
10280 				info->trigger.condition.roam_congestion.rx_tput)) {
10281 			hdd_err("roam_congestion.rx_tput put fail");
10282 			return -EINVAL;
10283 		}
10284 		if (nla_put_u32(skb, ROAM_STATS_CONGESTION_TX_TPUT,
10285 				info->trigger.condition.roam_congestion.tx_tput)) {
10286 			hdd_err("roam_congestion.tx_tput put fail");
10287 			return -EINVAL;
10288 		}
10289 		if (nla_put_u8(skb, ROAM_STATS_CONGESTION_ROAMABLE_CNT,
10290 			       info->trigger.condition.roam_congestion.roamable_count)) {
10291 			hdd_err("roam_congestion.roamable_count put fail");
10292 			return -EINVAL;
10293 		}
10294 		break;
10295 	case QCA_ROAM_REASON_BACKGROUND_SCAN:
10296 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI,
10297 			       info->trigger.condition.roam_background.current_rssi)) {
10298 			hdd_err("roam_background.current_rssi put fail");
10299 			return -EINVAL;
10300 		}
10301 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI,
10302 			       info->trigger.condition.roam_background.data_rssi)) {
10303 			hdd_err("roam_background.data_rssi put fail");
10304 			return -EINVAL;
10305 		}
10306 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH,
10307 			       info->trigger.condition.roam_background.data_rssi_threshold)) {
10308 			hdd_err("roam_background.data_rssi_threshold put fail");
10309 			return -EINVAL;
10310 		}
10311 		break;
10312 	case QCA_ROAM_REASON_USER_TRIGGER:
10313 		driver_invoke_reason =
10314 			info->trigger.condition.roam_user_trigger.invoke_reason;
10315 		vendor_invoke_reason = hdd_convert_roam_invoke_reason(driver_invoke_reason);
10316 		if (nla_put_u8(skb, ROAM_STATS_USER_TRIGGER_INVOKE_REASON,
10317 			       vendor_invoke_reason)) {
10318 			hdd_err("roam_user_trigger.invoke_reason put fail");
10319 			return -EINVAL;
10320 		}
10321 		break;
10322 	case QCA_ROAM_REASON_BTM:
10323 		if (nla_put_u8(skb, ROAM_STATS_BTM_REQUEST_MODE,
10324 			       info->trigger.condition.roam_btm.btm_request_mode)) {
10325 			hdd_err("roam_btm.btm_request_mode put fail");
10326 			return -EINVAL;
10327 		}
10328 		if (nla_put_u32(skb, ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME,
10329 				info->trigger.condition.roam_btm.disassoc_imminent_timer)) {
10330 			hdd_err("roam_btm.disassoc_imminent_timer put fail");
10331 			return -EINVAL;
10332 		}
10333 		if (nla_put_u32(skb, ROAM_STATS_BTM_VALID_INTERNAL,
10334 				info->trigger.condition.roam_btm.validity_internal)) {
10335 			hdd_err("roam_btm.validity_internal put fail");
10336 			return -EINVAL;
10337 		}
10338 		if (nla_put_u8(skb, ROAM_STATS_BTM_CANDIDATE_LIST_CNT,
10339 			       info->trigger.condition.roam_btm.candidate_list_count)) {
10340 			hdd_err("roam_btm.candidate_list_count put fail");
10341 			return -EINVAL;
10342 		}
10343 		if (nla_put_u8(skb, ROAM_STATS_BTM_RESPONSE_STATUS_CODE,
10344 			       info->trigger.condition.roam_btm.btm_response_status_code)) {
10345 			hdd_err("roam_btm.btm_response_status_code put fail");
10346 			return -EINVAL;
10347 		}
10348 		if (nla_put_u32(skb, ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT,
10349 				info->trigger.condition.roam_btm.btm_bss_termination_timeout)) {
10350 			hdd_err("roam btm_bss_termination_timeout put fail");
10351 			return -EINVAL;
10352 		}
10353 		if (nla_put_u32(skb, ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT,
10354 				info->trigger.condition.roam_btm.btm_mbo_assoc_retry_timeout)) {
10355 			hdd_err("roam btm_mbo_assoc_retry_timeout put fail");
10356 			return -EINVAL;
10357 		}
10358 		if (nla_put_u8(skb, ROAM_STATS_BTM_REQ_DIALOG_TOKEN,
10359 			       info->trigger.condition.roam_btm.btm_req_dialog_token)) {
10360 			hdd_err("roam_btm.btm_req_dialog_token put fail");
10361 			return -EINVAL;
10362 		}
10363 		break;
10364 	case QCA_ROAM_REASON_BSS_LOAD:
10365 		if (nla_put_u8(skb, ROAM_STATS_BSS_CU_LOAD,
10366 			       info->trigger.condition.roam_bss_load.cu_load)) {
10367 			hdd_err("roam_bss_load.cu_load put fail");
10368 			return -EINVAL;
10369 		}
10370 		break;
10371 	case QCA_ROAM_REASON_DISCONNECTION:
10372 		if (nla_put_u8(skb, ROAM_STATS_DISCONNECTION_TYPE,
10373 			       info->trigger.condition.roam_disconnection.deauth_type)) {
10374 			hdd_err("roam_disconnection.deauth_type put fail");
10375 			return -EINVAL;
10376 		}
10377 		if (nla_put_u16(skb, ROAM_STATS_DISCONNECTION_REASON,
10378 				info->trigger.condition.roam_disconnection.deauth_reason)) {
10379 			hdd_err("roam_disconnection.deauth_reason put fail");
10380 			return -EINVAL;
10381 		}
10382 		break;
10383 	case QCA_ROAM_REASON_STA_KICKOUT:
10384 		driver_tx_failures_reason =
10385 			info->trigger.condition.roam_tx_failures.kickout_threshold;
10386 		vendor_tx_failures_reason =
10387 			hdd_convert_roam_tx_failures_reason(driver_tx_failures_reason);
10388 		if (nla_put_u32(skb, ROAM_STATS_TX_FAILURES_THRESHOLD,
10389 				vendor_tx_failures_reason)) {
10390 			hdd_err("roam_tx_failures.kickout_threshold put fail");
10391 			return -EINVAL;
10392 		}
10393 		if (nla_put_u8(skb, ROAM_STATS_TX_FAILURES_REASON,
10394 			       info->trigger.condition.roam_tx_failures.kickout_reason)) {
10395 			hdd_err("roam_tx_failures.kickout_reason put fail");
10396 			return -EINVAL;
10397 		}
10398 		break;
10399 	default:
10400 		break;
10401 	}
10402 
10403 	vendor_scan_type = hdd_convert_roam_scan_type(info->trigger.roam_scan_type);
10404 	if (nla_put_u8(skb, ROAM_STATS_SCAN_TYPE, vendor_scan_type)) {
10405 		hdd_err("roam_scan_type put fail");
10406 		return -EINVAL;
10407 	}
10408 
10409 	if (nla_put_u8(skb, ROAM_STATS_ROAM_STATUS,
10410 		       info->trigger.roam_status)) {
10411 		hdd_err("roam_status put fail");
10412 		return -EINVAL;
10413 	}
10414 
10415 	if (info->trigger.roam_status) {
10416 		vendor_fail_reason = hdd_convert_roam_failures_reason(info->trigger.roam_fail_reason);
10417 		if (nla_put_u8(skb, ROAM_STATS_FAIL_REASON,
10418 			       vendor_fail_reason)) {
10419 			hdd_err("roam_fail_reason put fail");
10420 			return -EINVAL;
10421 		}
10422 
10423 		driver_abort_reason = info->trigger.abort.abort_reason_code;
10424 		vendor_abort_reason = hdd_convert_roam_abort_reason(driver_abort_reason);
10425 		if (info->trigger.abort.abort_reason_code) {
10426 			if (nla_put_u8(skb, ROAM_STATS_ABORT_REASON, vendor_abort_reason)) {
10427 				hdd_err("abort.abort_reason_code put fail");
10428 				return -EINVAL;
10429 			}
10430 			if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI,
10431 				       info->trigger.abort.data_rssi)) {
10432 				hdd_err("abort.data_rssi put fail");
10433 				return -EINVAL;
10434 			}
10435 			if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI_THRESHOLD,
10436 				       info->trigger.abort.data_rssi_threshold)) {
10437 				hdd_err("abort.data_rssi_threshold put fail");
10438 				return -EINVAL;
10439 			}
10440 			if (nla_put_u8(skb, ROAM_STATS_DATA_RX_LINKSPEED_STATUS,
10441 				       info->trigger.abort.rx_linkspeed_status)) {
10442 				hdd_err("abort.rx_linkspeed_status put fail");
10443 				return -EINVAL;
10444 			}
10445 		}
10446 	}
10447 
10448 	roam_chn_info = nla_nest_start(skb, ROAM_STATS_SCAN_CHAN_INFO);
10449 	if (!roam_chn_info) {
10450 		hdd_err("nla_nest_start fail");
10451 		return -EINVAL;
10452 	}
10453 
10454 	for (i = 0; i < info->scan.num_channels; i++) {
10455 		roam_chn = nla_nest_start(skb, i);
10456 		if (!roam_chn) {
10457 			hdd_err("nla_nest_start fail");
10458 			return -EINVAL;
10459 		}
10460 
10461 		if (nla_put_u32(skb, ROAM_STATS_SCAN_CHANNEL_FREQ,
10462 				info->scan.roam_chn[i].chan_freq)) {
10463 			hdd_err("roam_chn[%u].chan_freq put fail", i);
10464 			return -EINVAL;
10465 		}
10466 
10467 		driver_dwell_type = info->scan.roam_chn[i].dwell_type;
10468 		vendor_dwell_type = hdd_convert_roam_chn_dwell_type(driver_dwell_type);
10469 		if (nla_put_u32(skb, ROAM_STATS_SCAN_DWELL_TYPE,
10470 				vendor_dwell_type)) {
10471 			hdd_err("roam_chn[%u].dwell_type put fail", i);
10472 			return -EINVAL;
10473 		}
10474 		if (nla_put_u32(skb, ROAM_STATS_MAX_DWELL_TIME,
10475 				info->scan.roam_chn[i].max_dwell_time)) {
10476 			hdd_err("roam_chn[%u].max_dwell_time put fail", i);
10477 			return -EINVAL;
10478 		}
10479 		nla_nest_end(skb, roam_chn);
10480 	}
10481 	nla_nest_end(skb, roam_chn_info);
10482 
10483 	if (nla_put_u32(skb, ROAM_STATS_TOTAL_SCAN_TIME,
10484 			info->scan.total_scan_time)) {
10485 		hdd_err("roam_scan total_scan_time put fail");
10486 		return -EINVAL;
10487 	}
10488 
10489 	roam_frame_info = nla_nest_start(skb, ROAM_STATS_FRAME_INFO);
10490 	if (!roam_frame_info) {
10491 		hdd_err("nla_nest_start fail");
10492 		return -EINVAL;
10493 	}
10494 
10495 	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
10496 		if (info->timestamp[i].frame_type ==
10497 				WLAN_ROAM_STATS_FRAME_SUBTYPE_INVALID)
10498 			break;
10499 		roam_frame = nla_nest_start(skb, i);
10500 		if (!roam_frame) {
10501 			hdd_err("nla_nest_start fail");
10502 			return -EINVAL;
10503 		}
10504 		driver_frame_type = info->timestamp[i].frame_type;
10505 		vendor_frame_type = hdd_convert_roam_frame_type(driver_frame_type);
10506 		ret = nla_put_u8(skb, ROAM_STATS_FRAME_SUBTYPE,
10507 				 vendor_frame_type);
10508 		if (ret) {
10509 			hdd_err("roam_frame[%u].type put fail %d", i, ret);
10510 			return -EINVAL;
10511 		}
10512 		driver_frame_status = info->timestamp[i].status;
10513 		vendor_frame_status = hdd_convert_roam_frame_status(driver_frame_status);
10514 		ret = nla_put_u8(skb, ROAM_STATS_FRAME_STATUS,
10515 				 vendor_frame_status);
10516 		if (ret) {
10517 			hdd_err("frame[%u].status put fail %d", i, ret);
10518 			return -EINVAL;
10519 		}
10520 		ret = wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_FRAME_TIMESTAMP,
10521 						info->timestamp[i].timestamp);
10522 		if (ret) {
10523 			hdd_err("frame[%u].timestamp put fail %d", i, ret);
10524 			return -EINVAL;
10525 		}
10526 		ret = nla_put(skb,
10527 			      QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_BSSID,
10528 			      QDF_MAC_ADDR_SIZE,
10529 			      info->timestamp[i].bssid.bytes);
10530 		if (ret) {
10531 			hdd_err("roam candidate AP bssid put fail");
10532 			return -EINVAL;
10533 		}
10534 
10535 		nla_nest_end(skb, roam_frame);
10536 	}
10537 	nla_nest_end(skb, roam_frame_info);
10538 
10539 	if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ORIGINAL_BSSID,
10540 		    QDF_MAC_ADDR_SIZE, info->scan.original_bssid.bytes)) {
10541 		hdd_err("roam original AP bssid put fail");
10542 		return -EINVAL;
10543 	}
10544 	if (!info->trigger.roam_status) {
10545 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAMED_BSSID,
10546 			    QDF_MAC_ADDR_SIZE, info->scan.roamed_bssid.bytes)) {
10547 			hdd_err("roam roamed AP bssid put fail");
10548 			return -EINVAL;
10549 		}
10550 	}
10551 
10552 	return 0;
10553 }
10554 
10555 /**
10556  * hdd_get_roam_stats_info() - get roam statistics info to userspace,
10557  * for STA mode only
10558  * @skb:     pointer to sk buff
10559  * @hdd_ctx: pointer to hdd context
10560  * @roam_info: pointer to roam info
10561  * @roam_cache_num: roam cache number
10562  *
10563  * Return: 0 if success else error status
10564  */
hdd_get_roam_stats_info(struct sk_buff * skb,struct hdd_context * hdd_ctx,struct enhance_roam_info * roam_info,uint32_t roam_cache_num)10565 static int hdd_get_roam_stats_info(struct sk_buff *skb,
10566 				   struct hdd_context *hdd_ctx,
10567 				   struct enhance_roam_info *roam_info,
10568 				   uint32_t  roam_cache_num)
10569 {
10570 	struct nlattr *config, *roam_params;
10571 	uint32_t i;
10572 	int ret;
10573 
10574 	config = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO);
10575 	if (!config) {
10576 		hdd_err("nla nest start failure");
10577 		return -EINVAL;
10578 	}
10579 
10580 	/* Send all driver cached roam info to user space one time,
10581 	 * and don't flush them, since they will be cover by
10582 	 * new roam event info.
10583 	 */
10584 	for (i = 0; i < roam_cache_num; i++) {
10585 		roam_params = nla_nest_start(skb, i);
10586 		if (!roam_params)
10587 			return -EINVAL;
10588 
10589 		ret = hdd_nla_put_roam_stats_info(skb, roam_info, i);
10590 		if (ret) {
10591 			hdd_err("nla put failure");
10592 			return -EINVAL;
10593 		}
10594 
10595 		nla_nest_end(skb, roam_params);
10596 	}
10597 	nla_nest_end(skb, config);
10598 
10599 	return 0;
10600 }
10601 
10602 /**
10603  * hdd_get_roam_stats() - send roam statistics info to userspace
10604  * @hdd_ctx: pointer to hdd context
10605  * @adapter: pointer to adapter
10606  *
10607  * Return: 0 if success else error status
10608  */
10609 static int
hdd_get_roam_stats(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)10610 hdd_get_roam_stats(struct hdd_context *hdd_ctx,
10611 		   struct hdd_adapter *adapter)
10612 {
10613 	struct sk_buff *skb;
10614 	uint32_t skb_len;
10615 	int ret = 0;
10616 	struct wlan_objmgr_vdev *vdev;
10617 	QDF_STATUS status;
10618 	struct enhance_roam_info *roam_info = NULL;
10619 	uint32_t roam_num = 0;
10620 
10621 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
10622 					   WLAN_OSIF_STATS_ID);
10623 	if (!vdev)
10624 		return -EINVAL;
10625 
10626 	status = ucfg_cm_roam_stats_info_get(vdev, &roam_info, &roam_num);
10627 	if (QDF_IS_STATUS_ERROR(status)) {
10628 		hdd_err("Failed to get roam info : %d", status);
10629 		wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID);
10630 		return qdf_status_to_os_return(status);
10631 	}
10632 	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID);
10633 
10634 	skb_len = hdd_get_roam_stats_info_len(roam_info, roam_num);
10635 	if (!skb_len) {
10636 		hdd_err("No data requested");
10637 		ucfg_cm_roam_stats_info_put(roam_info);
10638 		return -EINVAL;
10639 	}
10640 
10641 	skb_len += NLMSG_HDRLEN;
10642 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len);
10643 	if (!skb) {
10644 		hdd_info("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
10645 		ucfg_cm_roam_stats_info_put(roam_info);
10646 		return -ENOMEM;
10647 	}
10648 
10649 	ret = hdd_get_roam_stats_info(skb, hdd_ctx, roam_info, roam_num);
10650 	if (ret) {
10651 		hdd_info("get roam stats fail");
10652 		wlan_cfg80211_vendor_free_skb(skb);
10653 		ucfg_cm_roam_stats_info_put(roam_info);
10654 		return -ENOMEM;
10655 	}
10656 
10657 	ucfg_cm_roam_stats_info_put(roam_info);
10658 
10659 	return wlan_cfg80211_vendor_cmd_reply(skb);
10660 }
10661 
10662 /**
10663  * __wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information
10664  * @wiphy: wiphy pointer
10665  * @wdev: pointer to struct wireless_dev
10666  * @data: pointer to incoming NL vendor data
10667  * @data_len: length of @data
10668  *
10669  * Return: 0 on success; error number otherwise.
10670  */
10671 static int
__wlan_hdd_cfg80211_get_roam_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)10672 __wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy,
10673 				   struct wireless_dev *wdev,
10674 				   const void *data,
10675 				   int data_len)
10676 {
10677 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
10678 	struct net_device *dev = wdev->netdev;
10679 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
10680 	int32_t status;
10681 
10682 	hdd_enter_dev(dev);
10683 
10684 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
10685 	    hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) {
10686 		hdd_err_rl("Command not allowed in FTM / Monitor mode");
10687 		status = -EPERM;
10688 		goto out;
10689 	}
10690 
10691 	status = wlan_hdd_validate_context(hdd_ctx);
10692 	if (status != 0)
10693 		goto out;
10694 
10695 	if (adapter->device_mode == QDF_STA_MODE) {
10696 		status = hdd_get_roam_stats(hdd_ctx, adapter);
10697 	} else {
10698 		hdd_err_rl("Invalid device_mode: %d", adapter->device_mode);
10699 		status = -EINVAL;
10700 	}
10701 
10702 	hdd_exit();
10703 out:
10704 	return status;
10705 }
10706 
10707 /**
10708  * wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information
10709  * @wiphy: wiphy pointer
10710  * @wdev: pointer to struct wireless_dev
10711  * @data: pointer to incoming NL vendor data
10712  * @data_len: length of @data
10713  *
10714  * Return: 0 on success; error number otherwise.
10715  */
wlan_hdd_cfg80211_get_roam_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)10716 int wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy,
10717 				     struct wireless_dev *wdev,
10718 				     const void *data,
10719 				     int data_len)
10720 {
10721 	int errno;
10722 	struct osif_vdev_sync *vdev_sync;
10723 
10724 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
10725 	if (errno)
10726 		return errno;
10727 
10728 	errno = __wlan_hdd_cfg80211_get_roam_stats(wiphy, wdev,
10729 						   data, data_len);
10730 
10731 	osif_vdev_sync_op_stop(vdev_sync);
10732 
10733 	return errno;
10734 }
10735 #endif
10736 
10737 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
10738 #ifdef WLAN_FEATURE_ROAM_INFO_STATS
10739 static void
wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info * link_info,struct roam_stats_event * roam_stats,uint8_t idx)10740 wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info *link_info,
10741 					       struct roam_stats_event *roam_stats,
10742 					       uint8_t idx)
10743 {
10744 	int status;
10745 	uint32_t data_size = 0;
10746 	struct sk_buff *vendor_event;
10747 	struct wlan_objmgr_vdev *vdev = NULL;
10748 	struct enhance_roam_info *roam_info = NULL;
10749 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
10750 
10751 	status = wlan_hdd_validate_context(hdd_ctx);
10752 	if (status) {
10753 		hdd_err("Invalid hdd_ctx");
10754 		return;
10755 	}
10756 
10757 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
10758 	if (!vdev)
10759 		return;
10760 	ucfg_cm_roam_info_get(vdev, &roam_info, idx);
10761 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
10762 
10763 	/* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */
10764 	data_size += nla_total_size(0);
10765 	/* nest attribute */
10766 	data_size += nla_total_size(0);
10767 
10768 	data_size += hdd_get_roam_stats_individual_record_len(roam_info, idx);
10769 
10770 	data_size += NLMSG_HDRLEN;
10771 
10772 	vendor_event =
10773 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
10774 						 &link_info->adapter->wdev,
10775 						 data_size,
10776 						 ROAM_STATS_EVENT_INDEX,
10777 						 GFP_KERNEL);
10778 
10779 	if (hdd_nla_put_roam_stats_info(vendor_event, roam_info, 0)) {
10780 		wlan_cfg80211_vendor_free_skb(vendor_event);
10781 		hdd_err("nla put failure");
10782 		return;
10783 	}
10784 
10785 	roam_stats->enhance_roam_rt_event = false;
10786 
10787 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
10788 }
10789 #else
10790 static void
wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info * link_info,struct roam_stats_event * roam_stats,uint8_t idx)10791 wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info *link_info,
10792 					       struct roam_stats_event *roam_stats,
10793 					       uint8_t idx)
10794 {
10795 }
10796 #endif
10797 void
wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event * roam_stats,uint8_t idx)10798 wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event *roam_stats,
10799 				       uint8_t idx)
10800 {
10801 	int status;
10802 	struct wlan_hdd_link_info *link_info;
10803 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
10804 
10805 	status = wlan_hdd_validate_context(hdd_ctx);
10806 	if (status) {
10807 		hdd_err("Invalid hdd_ctx");
10808 		return;
10809 	}
10810 
10811 	if (!roam_stats) {
10812 		hdd_err("msg received here is null");
10813 		return;
10814 	}
10815 
10816 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, roam_stats->vdev_id);
10817 	if (!link_info) {
10818 		hdd_err("vdev_id %d does not exist with host",
10819 			roam_stats->vdev_id);
10820 		return;
10821 	}
10822 	if (roam_stats->enhance_roam_rt_event)
10823 		wlan_hdd_cfg80211_enhance_roam_events_callback(link_info,
10824 							       roam_stats, idx);
10825 	else
10826 		wlan_hdd_cfg80211_typical_roam_events_callback(link_info,
10827 							       roam_stats, idx);
10828 }
10829 #endif
10830 
10831 #ifdef WLAN_FEATURE_TX_LATENCY_STATS
10832 #define TX_LATENCY_BUCKET_DISTRIBUTION_LEN \
10833 	(sizeof(uint32_t) * CDP_TX_LATENCY_TYPE_MAX)
10834 
10835 #define TX_LATENCY_ATTR(_name) QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ ## _name
10836 
10837 static const struct nla_policy
10838 tx_latency_bucket_policy[TX_LATENCY_ATTR(BUCKET_MAX) + 1] = {
10839 	[TX_LATENCY_ATTR(BUCKET_TYPE)] = {.type = NLA_U8},
10840 	[TX_LATENCY_ATTR(BUCKET_GRANULARITY)] = {.type = NLA_U32},
10841 	[TX_LATENCY_ATTR(BUCKET_AVERAGE)] = {.type = NLA_U32},
10842 	[TX_LATENCY_ATTR(BUCKET_DISTRIBUTION)] = {
10843 		.type = NLA_BINARY, .len = TX_LATENCY_BUCKET_DISTRIBUTION_LEN},
10844 };
10845 
10846 static const struct nla_policy
10847 tx_latency_link_policy[TX_LATENCY_ATTR(LINK_MAX) + 1] = {
10848 	[TX_LATENCY_ATTR(LINK_MAC_REMOTE)] = {
10849 		.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
10850 	[TX_LATENCY_ATTR(LINK_STAT_BUCKETS)] =
10851 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy),
10852 };
10853 
10854 const struct nla_policy
10855 tx_latency_policy[TX_LATENCY_ATTR(MAX) + 1] = {
10856 	[TX_LATENCY_ATTR(ACTION)] = {.type = NLA_U32},
10857 	[TX_LATENCY_ATTR(PERIODIC_REPORT)] = {.type = NLA_FLAG},
10858 	[TX_LATENCY_ATTR(PERIOD)] = {.type = NLA_U32 },
10859 	[TX_LATENCY_ATTR(BUCKETS)] =
10860 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy),
10861 	[TX_LATENCY_ATTR(LINKS)] =
10862 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_link_policy),
10863 };
10864 
10865 /**
10866  * struct tx_latency_link_node - Link info of remote peer
10867  * @node: list node for membership in the link list
10868  * @vdev_id: Unique value to identify VDEV
10869  * @mac_remote: link MAC address of the remote peer
10870  */
10871 struct tx_latency_link_node {
10872 	qdf_list_node_t node;
10873 	uint8_t vdev_id;
10874 	struct qdf_mac_addr mac_remote;
10875 };
10876 
10877 /**
10878  * hdd_tx_latency_set_for_link() - set tx latency stats config for a link
10879  * @link_info: link specific information
10880  * @config: pointer to tx latency stats config
10881  *
10882  * Return: QDF_STATUS
10883  */
10884 static inline QDF_STATUS
hdd_tx_latency_set_for_link(struct wlan_hdd_link_info * link_info,struct cdp_tx_latency_config * config)10885 hdd_tx_latency_set_for_link(struct wlan_hdd_link_info *link_info,
10886 			    struct cdp_tx_latency_config *config)
10887 {
10888 	QDF_STATUS status;
10889 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
10890 
10891 	if (!soc)
10892 		return QDF_STATUS_E_INVAL;
10893 
10894 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
10895 		return QDF_STATUS_SUCCESS;
10896 
10897 	status = cdp_host_tx_latency_stats_config(soc,
10898 						  link_info->vdev_id,
10899 						  config);
10900 	if (QDF_IS_STATUS_ERROR(status)) {
10901 		hdd_err_rl("failed to %s for vdev id %d, status %d",
10902 			   config->enable ? "enable" : "disable",
10903 			   link_info->vdev_id, status);
10904 		return status;
10905 	}
10906 
10907 	return QDF_STATUS_SUCCESS;
10908 }
10909 
10910 /**
10911  * hdd_tx_latency_restore_config() - restore tx latency stats config for a link
10912  * @link_info: link specific information
10913  *
10914  * Return: QDF_STATUS
10915  */
10916 QDF_STATUS
hdd_tx_latency_restore_config(struct wlan_hdd_link_info * link_info)10917 hdd_tx_latency_restore_config(struct wlan_hdd_link_info *link_info)
10918 {
10919 	QDF_STATUS status;
10920 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
10921 	struct cdp_tx_latency_config *config;
10922 
10923 	if (!soc)
10924 		return QDF_STATUS_E_INVAL;
10925 
10926 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
10927 		return QDF_STATUS_SUCCESS;
10928 
10929 	config = &link_info->adapter->tx_latency_cfg;
10930 	status = cdp_host_tx_latency_stats_config(soc,
10931 						  link_info->vdev_id,
10932 						  config);
10933 	if (QDF_IS_STATUS_ERROR(status)) {
10934 		hdd_err_rl("failed to %s for vdev id %d, status %d",
10935 			   config->enable ? "enable" : "disable",
10936 			   link_info->vdev_id, status);
10937 		return status;
10938 	}
10939 
10940 	return QDF_STATUS_SUCCESS;
10941 }
10942 
10943 /**
10944  * hdd_tx_latency_set() - restore tx latency stats config for a link
10945  * @adapter: pointer to hdd vdev/net_device context
10946  * @config: pointer to tx latency stats config
10947  *
10948  * Return: 0 on success; error number otherwise.
10949  */
10950 static int
hdd_tx_latency_set(struct hdd_adapter * adapter,struct cdp_tx_latency_config * config)10951 hdd_tx_latency_set(struct hdd_adapter *adapter,
10952 		   struct cdp_tx_latency_config *config)
10953 {
10954 	int ret;
10955 	struct wlan_hdd_link_info *link_info;
10956 	QDF_STATUS status = QDF_STATUS_E_NOENT;
10957 
10958 	ret = hdd_set_tsf_auto_report(adapter, config->enable,
10959 				      HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY);
10960 	if (ret) {
10961 		hdd_err_rl("failed to %s tsf auto report, ret %d",
10962 			   config->enable ? "enable" : "disable", ret);
10963 		return ret;
10964 	}
10965 
10966 	hdd_adapter_for_each_link_info(adapter, link_info) {
10967 		status = hdd_tx_latency_set_for_link(link_info, config);
10968 		if (QDF_IS_STATUS_ERROR(status))
10969 			break;
10970 	}
10971 
10972 	/* restore TSF auto report config on failure */
10973 	if (QDF_IS_STATUS_ERROR(status))
10974 		hdd_set_tsf_auto_report(adapter, !config->enable,
10975 					HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY);
10976 	else
10977 		qdf_mem_copy(&adapter->tx_latency_cfg, config,
10978 			     sizeof(*config));
10979 	hdd_debug("enable %d status %d", config->enable, status);
10980 	return qdf_status_to_os_return(status);
10981 }
10982 
10983 /**
10984  * hdd_tx_latency_fill_link_stats() - fill tx latency statistics info skb
10985  * @skb: skb to be filled
10986  * @latency: per link tx latency statistics
10987  * @idx: index of the nested attribute
10988  *
10989  * Return: 0 on success; error number otherwise.
10990  */
10991 static int
hdd_tx_latency_fill_link_stats(struct sk_buff * skb,struct cdp_tx_latency * latency,int idx)10992 hdd_tx_latency_fill_link_stats(struct sk_buff *skb,
10993 			       struct cdp_tx_latency *latency, int idx)
10994 {
10995 	struct nlattr *link, *link_stat_buckets, *link_stat_bucket;
10996 	uint32_t type;
10997 	int ret = 0;
10998 
10999 	link = nla_nest_start(skb, idx);
11000 	if (!link) {
11001 		ret = -ENOMEM;
11002 		goto err;
11003 	}
11004 
11005 	if (nla_put(skb, TX_LATENCY_ATTR(LINK_MAC_REMOTE),
11006 		    QDF_MAC_ADDR_SIZE, latency->mac_remote.bytes)) {
11007 		ret = -ENOMEM;
11008 		goto err;
11009 	}
11010 
11011 	hdd_debug_rl("idx %d link mac " QDF_MAC_ADDR_FMT,
11012 		     idx, QDF_MAC_ADDR_REF(latency->mac_remote.bytes));
11013 	link_stat_buckets =
11014 		nla_nest_start(skb, TX_LATENCY_ATTR(LINK_STAT_BUCKETS));
11015 	for (type = 0; type < CDP_TX_LATENCY_TYPE_MAX; type++) {
11016 		link_stat_bucket = nla_nest_start(skb, type);
11017 		if (!link_stat_bucket) {
11018 			ret = -ENOMEM;
11019 			goto err;
11020 		}
11021 
11022 		if (nla_put_u8(skb, TX_LATENCY_ATTR(BUCKET_TYPE), type)) {
11023 			ret = -ENOMEM;
11024 			goto err;
11025 		}
11026 
11027 		if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_GRANULARITY),
11028 				latency->stats[type].granularity)) {
11029 			ret = -ENOMEM;
11030 			goto err;
11031 		}
11032 
11033 		if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_AVERAGE),
11034 				latency->stats[type].average)) {
11035 			ret = -ENOMEM;
11036 			goto err;
11037 		}
11038 
11039 		if (nla_put(skb, TX_LATENCY_ATTR(BUCKET_DISTRIBUTION),
11040 			    TX_LATENCY_BUCKET_DISTRIBUTION_LEN,
11041 			    latency->stats[type].distribution)) {
11042 			ret = -ENOMEM;
11043 			goto err;
11044 		}
11045 
11046 		nla_nest_end(skb, link_stat_bucket);
11047 		hdd_debug_rl("	type %u granularity %u average %u",
11048 			     type, latency->stats[type].granularity,
11049 			     latency->stats[type].average);
11050 	}
11051 
11052 	nla_nest_end(skb, link_stat_buckets);
11053 	nla_nest_end(skb, link);
11054 
11055 err:
11056 	if (ret)
11057 		hdd_err("failed for link " QDF_MAC_ADDR_FMT " ret: %d",
11058 			QDF_MAC_ADDR_REF(latency->mac_remote.bytes), ret);
11059 	return ret;
11060 }
11061 
11062 /**
11063  * hdd_tx_latency_get_skb_len() - get required skb length for vendor command
11064  * response/async event
11065  * @num: required number of entries
11066  *
11067  * Return: the required skb length
11068  */
hdd_tx_latency_get_skb_len(uint32_t num)11069 static uint32_t hdd_tx_latency_get_skb_len(uint32_t num)
11070 {
11071 	int32_t peer_stat_sz = 0, per_bucket_len = 0, len;
11072 
11073 	if (!num)
11074 		return 0;
11075 
11076 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE */
11077 	per_bucket_len += nla_total_size(sizeof(uint8_t));
11078 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY */
11079 	per_bucket_len += nla_total_size(sizeof(uint32_t));
11080 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION */
11081 	per_bucket_len += nla_total_size(TX_LATENCY_BUCKET_DISTRIBUTION_LEN);
11082 	/* Nested attr */
11083 	per_bucket_len = nla_total_size(per_bucket_len);
11084 
11085 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE */
11086 	peer_stat_sz += nla_total_size(QDF_MAC_ADDR_SIZE);
11087 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS */
11088 	peer_stat_sz +=
11089 		nla_total_size(per_bucket_len * CDP_TX_LATENCY_TYPE_MAX);
11090 	/* Nested attr */
11091 	peer_stat_sz = nla_total_size(peer_stat_sz);
11092 
11093 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS */
11094 	len = nla_total_size(peer_stat_sz * num);
11095 	len += NLMSG_HDRLEN;
11096 	return len;
11097 }
11098 
11099 /**
11100  * hdd_tx_latency_link_list_free() - free all the nodes in the list
11101  * @list: list of the nodes for link info
11102  *
11103  * Return: None
11104  */
hdd_tx_latency_link_list_free(qdf_list_t * list)11105 static void hdd_tx_latency_link_list_free(qdf_list_t *list)
11106 {
11107 	struct tx_latency_link_node *entry, *next;
11108 
11109 	qdf_list_for_each_del(list, entry, next, node) {
11110 		qdf_list_remove_node(list, &entry->node);
11111 		qdf_mem_free(entry);
11112 	}
11113 }
11114 
11115 /**
11116  * hdd_tx_latency_link_list_add() - add a new node to the list for tx latency
11117  * links
11118  * @list: list of the nodes for link info
11119  * @vdev_id: Unique value to identify VDEV
11120  * @mac: link mac address of the remote peer
11121  *
11122  * Return: 0 on success; error number otherwise.
11123  */
11124 static int
hdd_tx_latency_link_list_add(qdf_list_t * list,uint8_t vdev_id,uint8_t * mac)11125 hdd_tx_latency_link_list_add(qdf_list_t *list, uint8_t vdev_id, uint8_t *mac)
11126 {
11127 	struct tx_latency_link_node *link;
11128 
11129 	link = (struct tx_latency_link_node *)qdf_mem_malloc(sizeof(*link));
11130 	if (!link)
11131 		return -ENOMEM;
11132 
11133 	qdf_mem_copy(link->mac_remote.bytes, mac, QDF_MAC_ADDR_SIZE);
11134 	link->vdev_id = vdev_id;
11135 	qdf_list_insert_back(list, &link->node);
11136 	return 0;
11137 }
11138 
11139 /**
11140  * hdd_tx_latency_get_links_from_attr() - parse information of the links from
11141  * attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11142  * @adapter: pointer to hdd vdev/net_device context
11143  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11144  * @list: list of the nodes for link info
11145  *
11146  * Return: 0 on success; error number otherwise.
11147  */
11148 static int
hdd_tx_latency_get_links_from_attr(struct hdd_adapter * adapter,struct nlattr * links_attr,qdf_list_t * list)11149 hdd_tx_latency_get_links_from_attr(struct hdd_adapter *adapter,
11150 				   struct nlattr *links_attr,
11151 				   qdf_list_t *list)
11152 {
11153 	struct nlattr *attr, *link_mac_remote_attr;
11154 	struct nlattr *tb[TX_LATENCY_ATTR(LINK_MAX) + 1];
11155 	int ret = 0, rem;
11156 	uint8_t vdev_id, *mac;
11157 
11158 	if (!links_attr || !list)
11159 		return -EINVAL;
11160 
11161 	/* links for MLO STA are attached to different vdevs */
11162 	vdev_id = (adapter->device_mode == QDF_STA_MODE ?
11163 		   CDP_VDEV_ALL : adapter->deflink->vdev_id);
11164 
11165 	nla_for_each_nested(attr, links_attr, rem) {
11166 		ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(LINK_MAX),
11167 					      nla_data(attr), nla_len(attr),
11168 					      tx_latency_link_policy);
11169 		if (ret) {
11170 			hdd_err("Attribute parse failed, ret %d", ret);
11171 			ret = -EINVAL;
11172 			goto out;
11173 		}
11174 
11175 		link_mac_remote_attr = tb[TX_LATENCY_ATTR(LINK_MAC_REMOTE)];
11176 		if (!link_mac_remote_attr) {
11177 			hdd_err("Missing link mac remote attribute");
11178 			ret = -EINVAL;
11179 			goto out;
11180 		}
11181 
11182 		if (nla_len(link_mac_remote_attr) < QDF_MAC_ADDR_SIZE) {
11183 			hdd_err("Attribute link mac remote is invalid");
11184 			ret = -EINVAL;
11185 			goto out;
11186 		}
11187 
11188 		mac = (uint8_t *)nla_data(link_mac_remote_attr);
11189 		ret = hdd_tx_latency_link_list_add(list, vdev_id, mac);
11190 		if (ret)
11191 			goto out;
11192 	}
11193 
11194 out:
11195 	if (ret)
11196 		hdd_tx_latency_link_list_free(list);
11197 
11198 	return ret;
11199 }
11200 
11201 /**
11202  * hdd_tx_latency_get_links_for_sap() - get all the active links for SAP mode
11203  * @adapter: pointer to hdd vdev/net_device context
11204  * @list: list of the nodes for link info
11205  *
11206  * Return: 0 on success; error number otherwise.
11207  */
11208 static int
hdd_tx_latency_get_links_for_sap(struct hdd_adapter * adapter,qdf_list_t * list)11209 hdd_tx_latency_get_links_for_sap(struct hdd_adapter *adapter, qdf_list_t *list)
11210 {
11211 	struct hdd_station_info *sta, *tmp = NULL;
11212 	int ret = 0;
11213 
11214 	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta, tmp,
11215 				  STA_INFO_SOFTAP_GET_STA_INFO) {
11216 		if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) {
11217 			hdd_put_sta_info_ref(&adapter->sta_info_list,
11218 					     &sta, true,
11219 					     STA_INFO_SOFTAP_GET_STA_INFO);
11220 			continue;
11221 		}
11222 
11223 		ret = hdd_tx_latency_link_list_add(list,
11224 						   adapter->deflink->vdev_id,
11225 						   sta->sta_mac.bytes);
11226 		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true,
11227 				     STA_INFO_SOFTAP_GET_STA_INFO);
11228 		if (ret)
11229 			goto out;
11230 	}
11231 
11232 out:
11233 	if (ret)
11234 		hdd_tx_latency_link_list_free(list);
11235 
11236 	return ret;
11237 }
11238 
11239 /**
11240  * hdd_tx_latency_get_links_for_sta() - get all the active links for station
11241  * mode
11242  * @adapter: pointer to hdd vdev/net_device context
11243  * @list: list of the nodes for link info
11244  *
11245  * Return: 0 on success; error number otherwise.
11246  */
11247 static int
hdd_tx_latency_get_links_for_sta(struct hdd_adapter * adapter,qdf_list_t * list)11248 hdd_tx_latency_get_links_for_sta(struct hdd_adapter *adapter, qdf_list_t *list)
11249 {
11250 	struct wlan_hdd_link_info *link_info;
11251 	struct hdd_station_ctx *ctx;
11252 	int ret = 0;
11253 
11254 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
11255 		if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
11256 			continue;
11257 
11258 		ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
11259 		if (!hdd_cm_is_vdev_associated(link_info))
11260 			continue;
11261 
11262 		ret = hdd_tx_latency_link_list_add(list, link_info->vdev_id,
11263 						   ctx->conn_info.bssid.bytes);
11264 		if (ret)
11265 			goto out;
11266 	}
11267 
11268 out:
11269 	if (ret)
11270 		hdd_tx_latency_link_list_free(list);
11271 
11272 	return ret;
11273 }
11274 
11275 /**
11276  * hdd_tx_latency_get_links() - get all the active links
11277  * @adapter: pointer to hdd vdev/net_device context
11278  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11279  * @list: list of the nodes for link info
11280  *
11281  * Return: 0 on success; error number otherwise.
11282  */
11283 static int
hdd_tx_latency_get_links(struct hdd_adapter * adapter,struct nlattr * links_attr,qdf_list_t * list)11284 hdd_tx_latency_get_links(struct hdd_adapter *adapter,
11285 			 struct nlattr *links_attr, qdf_list_t *list)
11286 {
11287 	if (!list)
11288 		return -EINVAL;
11289 
11290 	if (links_attr)
11291 		return hdd_tx_latency_get_links_from_attr(adapter,
11292 							  links_attr, list);
11293 
11294 	if (adapter->device_mode == QDF_SAP_MODE ||
11295 	    adapter->device_mode == QDF_P2P_GO_MODE)
11296 		return hdd_tx_latency_get_links_for_sap(adapter, list);
11297 	else if (adapter->device_mode == QDF_STA_MODE ||
11298 		 adapter->device_mode == QDF_P2P_CLIENT_MODE)
11299 		return hdd_tx_latency_get_links_for_sta(adapter, list);
11300 	else
11301 		return -ENOTSUPP;
11302 }
11303 
11304 /**
11305  * hdd_tx_latency_populate_links() - get per link tx latency stats and fill
11306  * into skb
11307  * @soc: pointer to soc context
11308  * @skb: skb for vendor command response/async event
11309  * @list: list of the nodes for link info
11310  *
11311  * Return: 0 on success; error number otherwise.
11312  */
11313 static inline int
hdd_tx_latency_populate_links(void * soc,struct sk_buff * skb,qdf_list_t * list)11314 hdd_tx_latency_populate_links(void *soc, struct sk_buff *skb, qdf_list_t *list)
11315 {
11316 	struct nlattr *links;
11317 	struct tx_latency_link_node *entry, *next;
11318 	struct cdp_tx_latency latency = {0};
11319 	int ret, idx = 0;
11320 	uint8_t *mac;
11321 	QDF_STATUS status;
11322 
11323 	links = nla_nest_start(skb, TX_LATENCY_ATTR(LINKS));
11324 	if (!links)
11325 		return -ENOMEM;
11326 
11327 	qdf_list_for_each_del(list, entry, next, node) {
11328 		qdf_list_remove_node(list, &entry->node);
11329 		mac = entry->mac_remote.bytes;
11330 		status = cdp_host_tx_latency_stats_fetch(soc, entry->vdev_id,
11331 							 mac, &latency);
11332 		if (QDF_IS_STATUS_ERROR(status)) {
11333 			qdf_mem_free(entry);
11334 			return qdf_status_to_os_return(status);
11335 		}
11336 
11337 		ret = hdd_tx_latency_fill_link_stats(skb, &latency, idx);
11338 		qdf_mem_free(entry);
11339 		if (ret)
11340 			return ret;
11341 
11342 		idx++;
11343 	}
11344 
11345 	nla_nest_end(skb, links);
11346 	return 0;
11347 }
11348 
11349 /**
11350  * hdd_tx_latency_get() - get per link tx latency stats
11351  * @wiphy: pointer to wiphy
11352  * @adapter: pointer to hdd vdev/net_device context
11353  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11354  *
11355  * Return: 0 on success; error number otherwise.
11356  */
11357 static int
hdd_tx_latency_get(struct wiphy * wiphy,struct hdd_adapter * adapter,struct nlattr * links_attr)11358 hdd_tx_latency_get(struct wiphy *wiphy,
11359 		   struct hdd_adapter *adapter, struct nlattr *links_attr)
11360 {
11361 	int ret;
11362 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
11363 	struct sk_buff *reply_skb = NULL;
11364 	uint32_t skb_len, links_num = 0;
11365 	qdf_list_t links_list;
11366 
11367 	if (!soc)
11368 		return -EINVAL;
11369 
11370 	qdf_list_create(&links_list, 0);
11371 	ret = hdd_tx_latency_get_links(adapter, links_attr, &links_list);
11372 	if (ret)
11373 		goto out;
11374 
11375 	links_num = qdf_list_size(&links_list);
11376 	if (!links_num) {
11377 		hdd_err_rl("no valid peers");
11378 		ret = -EINVAL;
11379 		goto out;
11380 	}
11381 
11382 	skb_len = hdd_tx_latency_get_skb_len(links_num);
11383 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
11384 	if (!reply_skb) {
11385 		ret = -ENOMEM;
11386 		goto out;
11387 	}
11388 
11389 	ret = hdd_tx_latency_populate_links(soc, reply_skb, &links_list);
11390 	if (ret)
11391 		goto free_skb;
11392 
11393 	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
11394 	/* skb has been consumed regardless of the return value */
11395 	goto out;
11396 
11397 free_skb:
11398 	wlan_cfg80211_vendor_free_skb(reply_skb);
11399 	hdd_tx_latency_link_list_free(&links_list);
11400 out:
11401 	qdf_list_destroy(&links_list);
11402 	hdd_debug_rl("get stats with ret %d", ret);
11403 	return ret;
11404 }
11405 
11406 /**
11407  * hdd_tx_latency_enable() - enable per link tx latency stats
11408  * @adapter: pointer to hdd vdev/net_device context
11409  * @period: statistical period for transmit latency
11410  * @periodic_report: whether driver needs to report transmit latency
11411  * statistics at the end of each period
11412  * @buckets_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS
11413  *
11414  * Return: 0 on success; error number otherwise.
11415  */
11416 static int
hdd_tx_latency_enable(struct hdd_adapter * adapter,uint32_t period,bool periodic_report,struct nlattr * buckets_attr)11417 hdd_tx_latency_enable(struct hdd_adapter *adapter, uint32_t period,
11418 		      bool periodic_report, struct nlattr *buckets_attr)
11419 {
11420 	struct nlattr *tb[TX_LATENCY_ATTR(BUCKET_MAX) + 1];
11421 	struct nlattr *attr, *bucket_type_attr, *bucket_granularity_attr;
11422 	int rem, ret;
11423 	uint8_t bucket_type;
11424 	struct cdp_tx_latency_config config = {0};
11425 
11426 	nla_for_each_nested(attr, buckets_attr, rem) {
11427 		ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(BUCKET_MAX),
11428 					      nla_data(attr), nla_len(attr),
11429 					      tx_latency_bucket_policy);
11430 		if (ret) {
11431 			hdd_err_rl("Attribute parse failed, ret %d", ret);
11432 			return -EINVAL;
11433 		}
11434 
11435 		bucket_type_attr = tb[TX_LATENCY_ATTR(BUCKET_TYPE)];
11436 		if (!bucket_type_attr) {
11437 			hdd_err_rl("Missing bucket type attribute");
11438 			return -EINVAL;
11439 		}
11440 
11441 		bucket_granularity_attr =
11442 			tb[TX_LATENCY_ATTR(BUCKET_GRANULARITY)];
11443 		if (!bucket_granularity_attr) {
11444 			hdd_err_rl("Missing bucket granularity attribute");
11445 			return -EINVAL;
11446 		}
11447 
11448 		bucket_type = nla_get_u8(bucket_type_attr);
11449 		if (bucket_type >= CDP_TX_LATENCY_TYPE_MAX) {
11450 			hdd_err_rl("Invalid bucket type %u", bucket_type);
11451 			return -EINVAL;
11452 		}
11453 
11454 		config.granularity[bucket_type] =
11455 			nla_get_u32(bucket_granularity_attr);
11456 		if (!config.granularity[bucket_type]) {
11457 			hdd_err_rl("Invalid granularity for type %d",
11458 				   bucket_type);
11459 			return -EINVAL;
11460 		}
11461 	}
11462 
11463 	for (rem = 0; rem < CDP_TX_LATENCY_TYPE_MAX; rem++) {
11464 		if (config.granularity[rem])
11465 			continue;
11466 
11467 		hdd_err_rl("Invalid granularity for type %d", rem);
11468 		return -EINVAL;
11469 	}
11470 
11471 	config.enable = true;
11472 	config.report = periodic_report;
11473 	config.period = period;
11474 	return hdd_tx_latency_set(adapter, &config);
11475 }
11476 
11477 /**
11478  * hdd_tx_latency_disable() - disable per link tx latency stats
11479  * @adapter: pointer to hdd vdev/net_device context
11480  *
11481  * Return: 0 on success; error number otherwise.
11482  */
hdd_tx_latency_disable(struct hdd_adapter * adapter)11483 static int hdd_tx_latency_disable(struct hdd_adapter *adapter)
11484 {
11485 	struct cdp_tx_latency_config config = {0};
11486 
11487 	return hdd_tx_latency_set(adapter, &config);
11488 }
11489 
11490 /**
11491  * __wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit
11492  * latency statistics
11493  * @wiphy: wiphy handle
11494  * @wdev: wdev handle
11495  * @data: user layer input
11496  * @data_len: length of user layer input
11497  *
11498  * this function is called in ssr protected environment.
11499  *
11500  * return: 0 success, none zero for failure
11501  */
11502 static int
__wlan_hdd_cfg80211_tx_latency(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)11503 __wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy, struct wireless_dev *wdev,
11504 			       const void *data, int data_len)
11505 {
11506 	int ret;
11507 	uint32_t action, period;
11508 	struct nlattr *period_attr, *buckets_attr, *links_attr;
11509 
11510 	struct net_device *dev = wdev->netdev;
11511 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
11512 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
11513 	struct nlattr *tb[TX_LATENCY_ATTR(MAX) + 1];
11514 	bool periodic_report;
11515 
11516 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
11517 		hdd_warn("command not allowed in ftm mode");
11518 		return -EPERM;
11519 	}
11520 
11521 	ret = wlan_hdd_validate_context(hdd_ctx);
11522 	if (ret)
11523 		return -EINVAL;
11524 
11525 	if (wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(MAX),
11526 				    data, data_len,
11527 				    tx_latency_policy)) {
11528 		hdd_err_rl("invalid attribute");
11529 		return -EINVAL;
11530 	}
11531 
11532 	if (!tb[TX_LATENCY_ATTR(ACTION)]) {
11533 		hdd_err_rl("no attr action");
11534 		return -EINVAL;
11535 	}
11536 
11537 	action = nla_get_u32(tb[TX_LATENCY_ATTR(ACTION)]);
11538 	switch (action) {
11539 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE:
11540 		if (!adapter->tx_latency_cfg.enable) {
11541 			ret = 0;
11542 			break;
11543 		}
11544 
11545 		ret = hdd_tx_latency_disable(adapter);
11546 		break;
11547 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE:
11548 		period_attr = tb[TX_LATENCY_ATTR(PERIOD)];
11549 		if (!period_attr) {
11550 			hdd_err_rl("no attr period");
11551 			return -EINVAL;
11552 		}
11553 
11554 		buckets_attr = tb[TX_LATENCY_ATTR(BUCKETS)];
11555 		if (!buckets_attr) {
11556 			hdd_err_rl("no attr buckets");
11557 			return -EINVAL;
11558 		}
11559 
11560 		period = nla_get_u32(period_attr);
11561 		if (!period) {
11562 			hdd_err_rl("invalid period");
11563 			return -EINVAL;
11564 		}
11565 
11566 		periodic_report =
11567 			nla_get_flag(tb[TX_LATENCY_ATTR(PERIODIC_REPORT)]);
11568 		ret = hdd_tx_latency_enable(adapter, period,
11569 					    periodic_report, buckets_attr);
11570 		break;
11571 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET:
11572 		if (!adapter->tx_latency_cfg.enable) {
11573 			hdd_err_rl("please enable the feature first");
11574 			ret = -EINVAL;
11575 			break;
11576 		}
11577 
11578 		links_attr = tb[TX_LATENCY_ATTR(LINKS)];
11579 		ret = hdd_tx_latency_get(wiphy, adapter, links_attr);
11580 		break;
11581 	default:
11582 		ret = -EINVAL;
11583 		break;
11584 	}
11585 
11586 	return ret;
11587 }
11588 
11589 /**
11590  * wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit latency
11591  * statistics
11592  * @wiphy: wiphy handle
11593  * @wdev: wdev handle
11594  * @data: user layer input
11595  * @data_len: length of user layer input
11596  *
11597  * return: 0 success, einval failure
11598  */
wlan_hdd_cfg80211_tx_latency(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)11599 int wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy,
11600 				 struct wireless_dev *wdev,
11601 				 const void *data, int data_len)
11602 {
11603 	int errno;
11604 	struct osif_vdev_sync *vdev_sync;
11605 
11606 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
11607 	if (errno)
11608 		return errno;
11609 
11610 	errno = __wlan_hdd_cfg80211_tx_latency(wiphy, wdev, data, data_len);
11611 	osif_vdev_sync_op_stop(vdev_sync);
11612 	return errno;
11613 }
11614 
11615 /**
11616  * hdd_tx_latency_stats_cb() - callback function for transmit latency stats
11617  * @vdev_id: Unique value to identify VDEV
11618  * @stats_list: list of the nodes for per-link transmit latency statistics
11619  *
11620  * Return: QDF_STATUS
11621  */
11622 static QDF_STATUS
hdd_tx_latency_stats_cb(uint8_t vdev_id,qdf_list_t * stats_list)11623 hdd_tx_latency_stats_cb(uint8_t vdev_id, qdf_list_t *stats_list)
11624 {
11625 	uint32_t len, stats_cnt;
11626 	struct sk_buff *vendor_event;
11627 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
11628 	struct wlan_hdd_link_info *link_info;
11629 	struct cdp_tx_latency *entry, *next;
11630 	struct nlattr *links;
11631 	int ret, idx = 0, flags = cds_get_gfp_flags();
11632 	int event_idx = QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY_INDEX;
11633 
11634 	if (!hdd_ctx) {
11635 		hdd_err("HDD context is NULL");
11636 		return QDF_STATUS_E_FAULT;
11637 	}
11638 
11639 	if (!stats_list || qdf_list_empty(stats_list)) {
11640 		hdd_err("invalid stats list");
11641 		return QDF_STATUS_E_INVAL;
11642 	}
11643 
11644 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
11645 	if (!link_info) {
11646 		hdd_err("adapter NULL for vdev id %d", vdev_id);
11647 		return QDF_STATUS_E_INVAL;
11648 	}
11649 
11650 	stats_cnt = qdf_list_size(stats_list);
11651 	len = hdd_tx_latency_get_skb_len(stats_cnt);
11652 	hdd_debug_rl("vdev id %d stats cnt %d", vdev_id, stats_cnt);
11653 	vendor_event =
11654 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
11655 						 &link_info->adapter->wdev,
11656 						 len, event_idx, flags);
11657 	if (!vendor_event) {
11658 		hdd_err("event alloc failed vdev id %d, len %d",
11659 			vdev_id, len);
11660 		return QDF_STATUS_E_NOMEM;
11661 	}
11662 
11663 	links = nla_nest_start(vendor_event, TX_LATENCY_ATTR(LINKS));
11664 	if (!links) {
11665 		wlan_cfg80211_vendor_free_skb(vendor_event);
11666 		hdd_err("failed to put peers");
11667 		return QDF_STATUS_E_NOMEM;
11668 	}
11669 
11670 	qdf_list_for_each_del(stats_list, entry, next, node) {
11671 		qdf_list_remove_node(stats_list, &entry->node);
11672 		ret = hdd_tx_latency_fill_link_stats(vendor_event, entry, idx);
11673 		qdf_mem_free(entry);
11674 		if (ret) {
11675 			hdd_err("failed to populate stats for idx %d", idx);
11676 			wlan_cfg80211_vendor_free_skb(vendor_event);
11677 			return QDF_STATUS_E_NOMEM;
11678 		}
11679 
11680 		idx++;
11681 	}
11682 
11683 	nla_nest_end(vendor_event, links);
11684 	wlan_cfg80211_vendor_event(vendor_event, flags);
11685 	return QDF_STATUS_SUCCESS;
11686 }
11687 
11688 /**
11689  * hdd_tx_latency_register_cb() - register callback function for transmit
11690  * latency stats
11691  * @soc: pointer to soc context
11692  *
11693  * Return: QDF_STATUS
11694  */
hdd_tx_latency_register_cb(void * soc)11695 QDF_STATUS hdd_tx_latency_register_cb(void *soc)
11696 {
11697 	hdd_debug("Register tx latency callback");
11698 	return cdp_host_tx_latency_stats_register_cb(soc,
11699 						     hdd_tx_latency_stats_cb);
11700 }
11701 #endif
11702 
11703 #ifdef WLAN_CHIPSET_STATS
11704 #ifdef CNSS_GENL
nl_srv_bcast_cstats(struct sk_buff * skb)11705 static int nl_srv_bcast_cstats(struct sk_buff *skb)
11706 {
11707 	return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
11708 }
11709 #else
nl_srv_bcast_cstats(struct sk_buff * skb)11710 static int nl_srv_bcast_cstats(struct sk_buff *skb)
11711 {
11712 	return nl_srv_bcast(skb);
11713 }
11714 #endif
11715 
hdd_cstats_send_data_to_userspace(char * buff,unsigned int len,enum cstats_types type)11716 int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len,
11717 				      enum cstats_types type)
11718 {
11719 	struct sk_buff *skb = NULL;
11720 	struct nlmsghdr *nlh;
11721 	tAniNlHdr *wnl;
11722 	static int nlmsg_seq;
11723 	int tot_msg_len;
11724 	int ret = -1;
11725 
11726 	if (type == CSTATS_HOST_TYPE) {
11727 		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_HOST_LOG_TYPE;
11728 		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
11729 	} else if (type == CSTATS_FW_TYPE) {
11730 		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_FW_LOG_TYPE;
11731 		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
11732 	}
11733 
11734 	skb = dev_alloc_skb(MAX_CSTATS_NODE_LENGTH);
11735 	if (!skb) {
11736 		qdf_err("dev_alloc_skb() failed");
11737 		return -ENOMEM;
11738 	}
11739 
11740 	tot_msg_len = NLMSG_SPACE(len + sizeof(wnl->radio));
11741 
11742 	nlh = nlmsg_put(skb, 0, nlmsg_seq++,
11743 			ANI_NL_MSG_LOG,
11744 			len + sizeof(wnl->radio), NLM_F_REQUEST);
11745 	if (!nlh) {
11746 		qdf_err("nlmsg_put() failed for msg size[%d]", tot_msg_len);
11747 		dev_kfree_skb(skb);
11748 		return -EINVAL;
11749 	}
11750 
11751 	wnl = (tAniNlHdr *)nlh;
11752 	wnl->radio = 0;
11753 
11754 	memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), buff, len);
11755 
11756 	ret = nl_srv_bcast_cstats(skb);
11757 	if (ret < 0)
11758 		qdf_err("Send Failed %d", ret);
11759 
11760 	return ret;
11761 }
11762 
11763 struct cstats_tx_rx_ops cstats_ops = {
11764 	.cstats_send_data_to_usr = hdd_cstats_send_data_to_userspace,
11765 };
11766 
hdd_register_cstats_ops(void)11767 void hdd_register_cstats_ops(void)
11768 {
11769 	ucfg_cp_stats_cstats_register_tx_rx_ops(&cstats_ops);
11770 }
11771 
11772 void
hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev * vdev,uint16_t transaction_id)11773 hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev,
11774 				  uint16_t transaction_id)
11775 {
11776 	struct cstats_nan_ndi_delete_req stat = {0};
11777 
11778 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_EVENT_ID;
11779 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_req) -
11780 			      sizeof(struct cstats_hdr);
11781 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11782 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11783 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11784 	stat.cmn.time_tick = qdf_get_log_timestamp();
11785 	stat.transaction_id = transaction_id;
11786 
11787 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_req), &stat);
11788 }
11789 
11790 void
hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info * li,struct nan_datapath_inf_create_rsp * ndi_rsp)11791 hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li,
11792 				   struct nan_datapath_inf_create_rsp *ndi_rsp)
11793 {
11794 	struct cstats_nan_ndi_create_resp stat = {0};
11795 	struct wlan_objmgr_vdev *vdev;
11796 	struct nan_vdev_priv_obj *priv_obj;
11797 
11798 	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_OSIF_NAN_ID);
11799 	if (!vdev) {
11800 		hdd_err("vdev is NULL");
11801 		return;
11802 	}
11803 
11804 	priv_obj = nan_get_vdev_priv_obj(vdev);
11805 	if (!priv_obj) {
11806 		hdd_err("priv_obj is null");
11807 		return;
11808 	}
11809 
11810 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_RESP_EVENT_ID;
11811 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_resp) -
11812 			      sizeof(struct cstats_hdr);
11813 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11814 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11815 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11816 	stat.cmn.time_tick = qdf_get_log_timestamp();
11817 	stat.status = ndi_rsp->status;
11818 	stat.reason = ndi_rsp->reason;
11819 	qdf_spin_lock_bh(&priv_obj->lock);
11820 	stat.transaction_id = priv_obj->ndp_create_transaction_id;
11821 	qdf_spin_unlock_bh(&priv_obj->lock);
11822 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
11823 
11824 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_resp),
11825 			       &stat);
11826 }
11827 
hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev * vdev,uint16_t transaction_id)11828 void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev,
11829 				       uint16_t transaction_id)
11830 {
11831 	struct cstats_nan_ndi_create_req stat = {0};
11832 
11833 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_EVENT_ID;
11834 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_req) -
11835 			      sizeof(struct cstats_hdr);
11836 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11837 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11838 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11839 	stat.cmn.time_tick = qdf_get_log_timestamp();
11840 	stat.transaction_id = transaction_id;
11841 
11842 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_req), &stat);
11843 }
11844 #endif /* WLAN_CHIPSET_STATS */
11845