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