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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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