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