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