1 /* 2 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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_cp_stats_mc_ucfg_api.c 22 * 23 * This file provide API definitions required for northbound interaction 24 */ 25 26 #include <wlan_objmgr_psoc_obj.h> 27 #include "wlan_cp_stats_mc_defs.h" 28 #include <wlan_cp_stats_mc_ucfg_api.h> 29 #include <wlan_cp_stats_mc_tgt_api.h> 30 #include <wlan_cp_stats_utils_api.h> 31 #include "../../core/src/wlan_cp_stats_defs.h" 32 #include "../../core/src/wlan_cp_stats_cmn_api_i.h" 33 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD 34 #include <wlan_pmo_obj_mgmt_api.h> 35 #endif 36 #ifdef WLAN_SUPPORT_TWT 37 #include <wlan_mlme_twt_public_struct.h> 38 #endif 39 #include <wlan_mlme_api.h> 40 41 #ifdef WLAN_SUPPORT_TWT 42 43 /** 44 * ucfg_twt_get_peer_session_param_by_dlg_id() - Finds a Peer twt session with 45 * dialog id matching with input dialog id. If a match is found copies 46 * the twt session parameters 47 * @mc_stats: pointer to peer specific stats 48 * @input_dialog_id: input dialog id 49 * @dest_param: Pointer to copy twt session parameters when a peer with 50 * given dialog id is found 51 * @num_twt_session: Pointer holding total number of valid twt session 52 * 53 * Return: Success if stats are copied for a peer with given dialog, 54 * else failure 55 */ 56 static QDF_STATUS ucfg_twt_get_peer_session_param_by_dlg_id(struct peer_mc_cp_stats * mc_stats,uint32_t input_dialog_id,struct wmi_host_twt_session_stats_info * dest_param,int * num_twt_session)57 ucfg_twt_get_peer_session_param_by_dlg_id(struct peer_mc_cp_stats *mc_stats, 58 uint32_t input_dialog_id, 59 struct wmi_host_twt_session_stats_info 60 *dest_param, int *num_twt_session) 61 { 62 struct wmi_host_twt_session_stats_info *src_param; 63 uint32_t event_type; 64 int i = 0; 65 QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; 66 67 if (!mc_stats || !dest_param) 68 return qdf_status; 69 70 for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { 71 event_type = mc_stats->twt_param[i].event_type; 72 73 src_param = &mc_stats->twt_param[i]; 74 if (!event_type || 75 (src_param->dialog_id != input_dialog_id && 76 input_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)) 77 continue; 78 79 if ((event_type == HOST_TWT_SESSION_SETUP) || 80 (event_type == HOST_TWT_SESSION_UPDATE)) { 81 qdf_mem_copy(&dest_param[*num_twt_session], src_param, 82 sizeof(*src_param)); 83 qdf_status = QDF_STATUS_SUCCESS; 84 *num_twt_session += 1; 85 if (*num_twt_session >= TWT_PEER_MAX_SESSIONS) 86 break; 87 } 88 } 89 90 return qdf_status; 91 } 92 93 /** 94 * ucfg_twt_get_single_peer_session_params()- Extracts twt session parameters 95 * corresponding to a peer given by dialog_id 96 * @psoc_obj: psoc object 97 * @mac_addr: mac addr of peer 98 * @dialog_id: dialog id of peer for which twt session params to be retrieved 99 * @params: pointer to store peer twt session parameters 100 * 101 * Return: total number of valid twt session 102 */ 103 static int ucfg_twt_get_single_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,uint8_t * mac_addr,uint32_t dialog_id,struct wmi_host_twt_session_stats_info * params)104 ucfg_twt_get_single_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, 105 uint8_t *mac_addr, uint32_t dialog_id, 106 struct wmi_host_twt_session_stats_info 107 *params) 108 { 109 struct wlan_objmgr_peer *peer; 110 struct peer_cp_stats *peer_cp_stats_priv; 111 struct peer_mc_cp_stats *peer_mc_stats; 112 QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; 113 int num_twt_session = 0; 114 115 if (!psoc_obj || !params) 116 return num_twt_session; 117 118 peer = wlan_objmgr_get_peer_by_mac(psoc_obj, mac_addr, 119 WLAN_CP_STATS_ID); 120 if (!peer) 121 return num_twt_session; 122 123 peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); 124 if (!peer_cp_stats_priv) { 125 wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); 126 return num_twt_session; 127 } 128 129 wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); 130 peer_mc_stats = peer_cp_stats_priv->peer_stats; 131 132 qdf_status = ucfg_twt_get_peer_session_param_by_dlg_id( 133 peer_mc_stats, 134 dialog_id, 135 params, 136 &num_twt_session); 137 if (QDF_IS_STATUS_ERROR(qdf_status)) { 138 qdf_err("No TWT session for " QDF_MAC_ADDR_FMT " dialog_id %d", 139 QDF_MAC_ADDR_REF(mac_addr), dialog_id); 140 } 141 142 wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); 143 wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); 144 145 return num_twt_session; 146 } 147 148 /** 149 * ucfg_twt_get_peer_session_param() - Obtains twt session parameters of 150 * a peer if twt session is valid 151 * @mc_cp_stats: pointer to peer specific stats 152 * @params: Pointer to copy twt session parameters 153 * @num_twt_session: Pointer holding total number of valid twt sessions 154 * 155 * Return: QDF_STATUS success if valid twt session parameters are obtained 156 * else other qdf error values 157 */ 158 static QDF_STATUS ucfg_twt_get_peer_session_param(struct peer_mc_cp_stats * mc_cp_stats,struct wmi_host_twt_session_stats_info * params,int * num_twt_session)159 ucfg_twt_get_peer_session_param(struct peer_mc_cp_stats *mc_cp_stats, 160 struct wmi_host_twt_session_stats_info *params, 161 int *num_twt_session) 162 { 163 struct wmi_host_twt_session_stats_info *twt_params; 164 QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; 165 uint32_t event_type; 166 int i; 167 168 if (!mc_cp_stats || !params) 169 return qdf_status; 170 171 for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { 172 twt_params = &mc_cp_stats->twt_param[i]; 173 event_type = mc_cp_stats->twt_param[i].event_type; 174 175 /* Check twt session is established */ 176 if ((event_type == HOST_TWT_SESSION_SETUP) || 177 (event_type == HOST_TWT_SESSION_UPDATE)) { 178 qdf_mem_copy(¶ms[*num_twt_session], twt_params, 179 sizeof(*twt_params)); 180 qdf_status = QDF_STATUS_SUCCESS; 181 *num_twt_session += 1; 182 } 183 } 184 return qdf_status; 185 } 186 187 /** 188 * ucfg_twt_get_all_peer_session_params()- Retrieves twt session parameters 189 * of all peers with valid twt session 190 * @psoc_obj: psoc object 191 * @vdev_id: vdev_id 192 * @params: array of pointer to store peer twt session parameters 193 * 194 * Return: total number of valid twt sessions 195 */ 196 static int ucfg_twt_get_all_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,uint8_t vdev_id,struct wmi_host_twt_session_stats_info * params)197 ucfg_twt_get_all_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, 198 uint8_t vdev_id, 199 struct wmi_host_twt_session_stats_info 200 *params) 201 { 202 qdf_list_t *peer_list; 203 struct wlan_objmgr_peer *peer, *peer_next; 204 struct wlan_objmgr_vdev *vdev; 205 struct peer_cp_stats *cp_stats_peer_obj, *peer_cp_stat_prv; 206 struct peer_mc_cp_stats *mc_cp_stats; 207 int num_twt_session = 0; 208 enum QDF_OPMODE opmode; 209 int sap_max_peer = 0; 210 211 if (!psoc_obj) { 212 cp_stats_err("psoc is NULL"); 213 return num_twt_session; 214 } 215 216 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc_obj, vdev_id, 217 WLAN_CP_STATS_ID); 218 219 if (!vdev) { 220 cp_stats_err("vdev is NULL, vdev_id: %d", vdev_id); 221 return num_twt_session; 222 } 223 224 wlan_mlme_get_sap_max_peers(psoc_obj, &sap_max_peer); 225 opmode = wlan_vdev_mlme_get_opmode(vdev); 226 227 peer_list = &vdev->vdev_objmgr.wlan_peer_list; 228 if (!peer_list) { 229 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 230 cp_stats_err("Peer list for vdev obj is NULL"); 231 return num_twt_session; 232 } 233 234 peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, 235 WLAN_CP_STATS_ID); 236 237 while (peer) { 238 cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj( 239 peer, WLAN_UMAC_COMP_CP_STATS); 240 241 mc_cp_stats = NULL; 242 if (cp_stats_peer_obj) 243 mc_cp_stats = cp_stats_peer_obj->peer_stats; 244 245 peer_cp_stat_prv = 246 wlan_cp_stats_get_peer_stats_obj(peer); 247 248 if (peer_cp_stat_prv && mc_cp_stats) { 249 wlan_cp_stats_peer_obj_lock(peer_cp_stat_prv); 250 ucfg_twt_get_peer_session_param(mc_cp_stats, 251 params, 252 &num_twt_session); 253 wlan_cp_stats_peer_obj_unlock(peer_cp_stat_prv); 254 } 255 256 if (opmode == QDF_STA_MODE && 257 num_twt_session >= TWT_PEER_MAX_SESSIONS) { 258 wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); 259 goto done; 260 } 261 262 if (opmode == QDF_SAP_MODE && 263 num_twt_session >= (sap_max_peer * TWT_PEER_MAX_SESSIONS)) { 264 wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); 265 goto done; 266 } 267 268 peer_next = wlan_peer_get_next_active_peer_of_vdev( 269 vdev, peer_list, peer, 270 WLAN_CP_STATS_ID); 271 wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); 272 peer = peer_next; 273 } 274 275 done: 276 if (!num_twt_session) 277 cp_stats_err("Unable to find a peer with twt session established"); 278 279 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 280 return num_twt_session; 281 } 282 283 int ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,struct wmi_host_twt_session_stats_info * params)284 ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, 285 struct wmi_host_twt_session_stats_info *params) 286 { 287 uint8_t *mac_addr; 288 uint32_t dialog_id; 289 uint8_t vdev_id; 290 int num_twt_session = 0; 291 292 if (!psoc_obj || !params) 293 return num_twt_session; 294 295 mac_addr = params[0].peer_mac; 296 dialog_id = params[0].dialog_id; 297 vdev_id = params[0].vdev_id; 298 299 /* 300 * Currently for STA case, twt_get_params nl is sending only dialog_id 301 * and mac_addr is being filled by driver in STA peer case. 302 * For SAP case, twt_get_params nl is sending dialog_id and 303 * peer mac_addr. When twt_get_params add mac_addr and dialog_id of 304 * STA/SAP, we need handle unicast/multicast macaddr in 305 * ucfg_twt_get_peer_session_params. 306 */ 307 if (!QDF_IS_ADDR_BROADCAST(mac_addr)) 308 num_twt_session = ucfg_twt_get_single_peer_session_params( 309 psoc_obj, 310 mac_addr, 311 dialog_id, 312 params); 313 else 314 num_twt_session = ucfg_twt_get_all_peer_session_params( 315 psoc_obj, 316 vdev_id, 317 params); 318 319 return num_twt_session; 320 } 321 #endif /* WLAN_SUPPORT_TWT */ 322 wlan_cp_stats_psoc_cs_init(struct psoc_cp_stats * psoc_cs)323 QDF_STATUS wlan_cp_stats_psoc_cs_init(struct psoc_cp_stats *psoc_cs) 324 { 325 psoc_cs->obj_stats = qdf_mem_malloc(sizeof(struct psoc_mc_cp_stats)); 326 if (!psoc_cs->obj_stats) 327 return QDF_STATUS_E_NOMEM; 328 329 return QDF_STATUS_SUCCESS; 330 } 331 wlan_cp_stats_psoc_cs_deinit(struct psoc_cp_stats * psoc_cs)332 QDF_STATUS wlan_cp_stats_psoc_cs_deinit(struct psoc_cp_stats *psoc_cs) 333 { 334 qdf_mem_free(psoc_cs->obj_stats); 335 psoc_cs->obj_stats = NULL; 336 return QDF_STATUS_SUCCESS; 337 } 338 wlan_cp_stats_vdev_cs_init(struct vdev_cp_stats * vdev_cs)339 QDF_STATUS wlan_cp_stats_vdev_cs_init(struct vdev_cp_stats *vdev_cs) 340 { 341 vdev_cs->vdev_stats = qdf_mem_malloc(sizeof(struct vdev_mc_cp_stats)); 342 if (!vdev_cs->vdev_stats) 343 return QDF_STATUS_E_NOMEM; 344 345 return QDF_STATUS_SUCCESS; 346 } 347 wlan_cp_stats_vdev_cs_deinit(struct vdev_cp_stats * vdev_cs)348 QDF_STATUS wlan_cp_stats_vdev_cs_deinit(struct vdev_cp_stats *vdev_cs) 349 { 350 qdf_mem_free(vdev_cs->vdev_stats); 351 vdev_cs->vdev_stats = NULL; 352 return QDF_STATUS_SUCCESS; 353 } 354 wlan_cp_stats_pdev_cs_init(struct pdev_cp_stats * pdev_cs)355 QDF_STATUS wlan_cp_stats_pdev_cs_init(struct pdev_cp_stats *pdev_cs) 356 { 357 pdev_cs->pdev_stats = qdf_mem_malloc(sizeof(struct pdev_mc_cp_stats)); 358 if (!pdev_cs->pdev_stats) 359 return QDF_STATUS_E_NOMEM; 360 361 return QDF_STATUS_SUCCESS; 362 } 363 wlan_cp_stats_pdev_cs_deinit(struct pdev_cp_stats * pdev_cs)364 QDF_STATUS wlan_cp_stats_pdev_cs_deinit(struct pdev_cp_stats *pdev_cs) 365 { 366 qdf_mem_free(pdev_cs->pdev_stats); 367 pdev_cs->pdev_stats = NULL; 368 return QDF_STATUS_SUCCESS; 369 } 370 wlan_cp_stats_peer_cs_init(struct peer_cp_stats * peer_cs)371 QDF_STATUS wlan_cp_stats_peer_cs_init(struct peer_cp_stats *peer_cs) 372 { 373 struct peer_mc_cp_stats *peer_mc_stats; 374 375 peer_mc_stats = qdf_mem_malloc(sizeof(struct peer_mc_cp_stats)); 376 if (!peer_mc_stats) 377 return QDF_STATUS_E_NOMEM; 378 379 peer_mc_stats->adv_stats = 380 qdf_mem_malloc(sizeof(struct peer_adv_mc_cp_stats)); 381 382 if (!peer_mc_stats->adv_stats) { 383 qdf_mem_free(peer_mc_stats); 384 peer_mc_stats = NULL; 385 return QDF_STATUS_E_NOMEM; 386 } 387 388 peer_mc_stats->extd_stats = 389 qdf_mem_malloc(sizeof(struct peer_extd_stats)); 390 391 if (!peer_mc_stats->extd_stats) { 392 qdf_mem_free(peer_mc_stats->adv_stats); 393 peer_mc_stats->adv_stats = NULL; 394 qdf_mem_free(peer_mc_stats); 395 peer_mc_stats = NULL; 396 return QDF_STATUS_E_NOMEM; 397 } 398 peer_cs->peer_stats = peer_mc_stats; 399 400 return QDF_STATUS_SUCCESS; 401 } 402 wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats * peer_cs)403 QDF_STATUS wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats *peer_cs) 404 { 405 struct peer_mc_cp_stats *peer_mc_stats = peer_cs->peer_stats; 406 407 qdf_mem_free(peer_mc_stats->adv_stats); 408 peer_mc_stats->adv_stats = NULL; 409 qdf_mem_free(peer_mc_stats->extd_stats); 410 peer_mc_stats->extd_stats = NULL; 411 qdf_mem_free(peer_cs->peer_stats); 412 peer_cs->peer_stats = NULL; 413 414 return QDF_STATUS_SUCCESS; 415 } 416 ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum qdf_proto_subtype protocol)417 QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol( 418 struct wlan_objmgr_psoc *psoc, 419 uint8_t vdev_id, 420 enum qdf_proto_subtype protocol) 421 { 422 struct wake_lock_stats *stats; 423 struct psoc_cp_stats *psoc_cp_stats_priv; 424 struct psoc_mc_cp_stats *psoc_mc_stats; 425 426 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 427 if (!psoc_cp_stats_priv) { 428 cp_stats_err("psoc cp stats object is null"); 429 return QDF_STATUS_E_NULL_VALUE; 430 } 431 432 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 433 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 434 435 if (!psoc_mc_stats) { 436 cp_stats_err("psoc mc stats is null"); 437 return QDF_STATUS_E_NULL_VALUE; 438 } 439 440 stats = &psoc_mc_stats->wow_stats; 441 switch (protocol) { 442 case QDF_PROTO_ICMP_REQ: 443 case QDF_PROTO_ICMP_RES: 444 stats->icmpv4_count++; 445 break; 446 case QDF_PROTO_ICMPV6_REQ: 447 case QDF_PROTO_ICMPV6_RES: 448 case QDF_PROTO_ICMPV6_RS: 449 stats->icmpv6_count++; 450 break; 451 case QDF_PROTO_ICMPV6_RA: 452 stats->icmpv6_count++; 453 stats->ipv6_mcast_ra_stats++; 454 break; 455 case QDF_PROTO_ICMPV6_NS: 456 stats->icmpv6_count++; 457 stats->ipv6_mcast_ns_stats++; 458 break; 459 case QDF_PROTO_ICMPV6_NA: 460 stats->icmpv6_count++; 461 stats->ipv6_mcast_na_stats++; 462 break; 463 default: 464 break; 465 } 466 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 467 468 return QDF_STATUS_SUCCESS; 469 } 470 ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t * dest_mac)471 QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr( 472 struct wlan_objmgr_psoc *psoc, 473 uint8_t vdev_id, uint8_t *dest_mac) 474 { 475 struct psoc_cp_stats *psoc_cp_stats_priv; 476 struct psoc_mc_cp_stats *psoc_mc_stats; 477 struct wake_lock_stats *stats; 478 479 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 480 if (!psoc_cp_stats_priv) { 481 cp_stats_err("psoc cp stats object is null"); 482 return QDF_STATUS_E_NULL_VALUE; 483 } 484 485 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 486 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 487 if (!psoc_mc_stats) { 488 cp_stats_err("psoc mc stats is null"); 489 return QDF_STATUS_E_NULL_VALUE; 490 } 491 492 stats = &psoc_mc_stats->wow_stats; 493 494 switch (*dest_mac) { 495 case QDF_BCAST_MAC_ADDR: 496 stats->bcast_wake_up_count++; 497 break; 498 case QDF_MCAST_IPV4_MAC_ADDR: 499 stats->ipv4_mcast_wake_up_count++; 500 break; 501 case QDF_MCAST_IPV6_MAC_ADDR: 502 stats->ipv6_mcast_wake_up_count++; 503 break; 504 default: 505 stats->ucast_wake_up_count++; 506 break; 507 } 508 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 509 510 return QDF_STATUS_SUCCESS; 511 } 512 ucfg_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint32_t reason)513 QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc, 514 uint8_t vdev_id, 515 uint32_t reason) 516 { 517 struct wake_lock_stats *stats; 518 QDF_STATUS status = QDF_STATUS_SUCCESS; 519 struct psoc_mc_cp_stats *psoc_mc_stats; 520 struct psoc_cp_stats *psoc_cp_stats_priv; 521 522 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 523 if (!psoc_cp_stats_priv) { 524 cp_stats_err("psoc cp stats object is null"); 525 return QDF_STATUS_E_NULL_VALUE; 526 } 527 528 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 529 530 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 531 532 if (!psoc_mc_stats) { 533 cp_stats_err("psoc mc stats is null"); 534 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 535 return QDF_STATUS_E_NULL_VALUE; 536 } 537 538 stats = &psoc_mc_stats->wow_stats; 539 540 status = tgt_mc_cp_stats_inc_wake_lock_stats(psoc, reason, stats, 541 &psoc_mc_stats->wow_unspecified_wake_up_count); 542 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 543 544 return status; 545 } 546 547 /** 548 * vdev_iterator() - iterator function to collect wake_lock_stats from all vdev 549 * @psoc: pointer to psoc object 550 * @vdev: pointer to vdev object 551 * @arg: stats object pointer passed as arg 552 * 553 * Return - none 554 */ vdev_iterator(struct wlan_objmgr_psoc * psoc,void * vdev,void * arg)555 static void vdev_iterator(struct wlan_objmgr_psoc *psoc, void *vdev, void *arg) 556 { 557 struct wake_lock_stats *vdev_stats; 558 struct wake_lock_stats *stats = arg; 559 struct psoc_cp_stats *psoc_cp_stats_priv; 560 struct psoc_mc_cp_stats *psoc_mc_stats; 561 562 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 563 if (!psoc_cp_stats_priv) { 564 cp_stats_err("psoc cp stats object is null"); 565 return; 566 } 567 568 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 569 if (!psoc_mc_stats) { 570 cp_stats_err("psoc mc stats is null"); 571 return; 572 } 573 574 vdev_stats = &psoc_mc_stats->wow_stats; 575 576 stats->ucast_wake_up_count += vdev_stats->ucast_wake_up_count; 577 stats->bcast_wake_up_count += vdev_stats->bcast_wake_up_count; 578 stats->ipv4_mcast_wake_up_count += vdev_stats->ipv4_mcast_wake_up_count; 579 stats->ipv6_mcast_wake_up_count += vdev_stats->ipv6_mcast_wake_up_count; 580 stats->ipv6_mcast_ra_stats += vdev_stats->ipv6_mcast_ra_stats; 581 stats->ipv6_mcast_ns_stats += vdev_stats->ipv6_mcast_ns_stats; 582 stats->ipv6_mcast_na_stats += vdev_stats->ipv6_mcast_na_stats; 583 stats->icmpv4_count += vdev_stats->icmpv4_count; 584 stats->icmpv6_count += vdev_stats->icmpv6_count; 585 stats->rssi_breach_wake_up_count += 586 vdev_stats->rssi_breach_wake_up_count; 587 stats->low_rssi_wake_up_count += vdev_stats->low_rssi_wake_up_count; 588 stats->gscan_wake_up_count += vdev_stats->gscan_wake_up_count; 589 stats->pno_complete_wake_up_count += 590 vdev_stats->pno_complete_wake_up_count; 591 stats->pno_match_wake_up_count += vdev_stats->pno_match_wake_up_count; 592 stats->oem_response_wake_up_count += 593 vdev_stats->oem_response_wake_up_count; 594 stats->uc_drop_wake_up_count += vdev_stats->uc_drop_wake_up_count; 595 stats->fatal_event_wake_up_count += 596 vdev_stats->fatal_event_wake_up_count; 597 stats->pwr_save_fail_detected += vdev_stats->pwr_save_fail_detected; 598 stats->scan_11d += vdev_stats->scan_11d; 599 } 600 ucfg_mc_cp_stats_get_psoc_wake_lock_stats(struct wlan_objmgr_psoc * psoc,struct wake_lock_stats * stats)601 QDF_STATUS ucfg_mc_cp_stats_get_psoc_wake_lock_stats( 602 struct wlan_objmgr_psoc *psoc, 603 struct wake_lock_stats *stats) 604 { 605 struct psoc_cp_stats *psoc_cp_stats_priv; 606 struct psoc_mc_cp_stats *psoc_mc_stats; 607 608 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 609 if (!psoc_cp_stats_priv) { 610 cp_stats_err("psoc cp stats object is null"); 611 return QDF_STATUS_E_NULL_VALUE; 612 } 613 614 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 615 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 616 /* iterate through all vdevs, and get wow stats from vdev_cs object */ 617 wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, vdev_iterator, 618 stats, true, WLAN_CP_STATS_ID); 619 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 620 621 return QDF_STATUS_SUCCESS; 622 } 623 ucfg_mc_cp_stats_get_vdev_wake_lock_stats(struct wlan_objmgr_vdev * vdev,struct wake_lock_stats * stats)624 QDF_STATUS ucfg_mc_cp_stats_get_vdev_wake_lock_stats( 625 struct wlan_objmgr_vdev *vdev, 626 struct wake_lock_stats *stats) 627 { 628 struct wlan_objmgr_psoc *psoc; 629 struct psoc_cp_stats *psoc_cp_stats_priv; 630 struct psoc_mc_cp_stats *psoc_mc_stats; 631 632 wlan_vdev_obj_lock(vdev); 633 psoc = wlan_vdev_get_psoc(vdev); 634 if (!psoc) { 635 wlan_vdev_obj_unlock(vdev); 636 cp_stats_err("psoc NULL"); 637 return QDF_STATUS_E_INVAL; 638 } 639 wlan_vdev_obj_unlock(vdev); 640 641 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 642 if (!psoc_cp_stats_priv) { 643 cp_stats_err("psoc cp stats object is null"); 644 return QDF_STATUS_E_NULL_VALUE; 645 } 646 647 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 648 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 649 650 if (!psoc_mc_stats) { 651 cp_stats_err("psoc mc stats is null"); 652 return QDF_STATUS_E_NULL_VALUE; 653 } 654 655 qdf_mem_copy(stats, &psoc_mc_stats->wow_stats, sizeof(*stats)); 656 657 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 658 659 return QDF_STATUS_SUCCESS; 660 } 661 ucfg_mc_cp_stats_write_wow_stats(struct wlan_objmgr_psoc * psoc,char * buffer,uint16_t max_len,int * ret)662 QDF_STATUS ucfg_mc_cp_stats_write_wow_stats( 663 struct wlan_objmgr_psoc *psoc, 664 char *buffer, uint16_t max_len, int *ret) 665 { 666 QDF_STATUS status; 667 uint32_t unspecified_wake_count; 668 struct wake_lock_stats wow_stats = {0}; 669 struct psoc_mc_cp_stats *psoc_mc_stats; 670 struct psoc_cp_stats *psoc_cp_stats_priv; 671 672 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 673 if (!psoc_cp_stats_priv) { 674 cp_stats_err("psoc cp stats object is null"); 675 return QDF_STATUS_E_NULL_VALUE; 676 } 677 678 /* get stats from psoc */ 679 status = ucfg_mc_cp_stats_get_psoc_wake_lock_stats(psoc, &wow_stats); 680 if (QDF_IS_STATUS_ERROR(status)) { 681 cp_stats_err("Failed to get WoW stats"); 682 return status; 683 } 684 685 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 686 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 687 unspecified_wake_count = psoc_mc_stats->wow_unspecified_wake_up_count; 688 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 689 690 *ret = qdf_scnprintf(buffer, max_len, 691 "WoW Wake Reasons\n" 692 "\tunspecified wake count: %u\n" 693 "\tunicast: %u\n" 694 "\tbroadcast: %u\n" 695 "\tIPv4 multicast: %u\n" 696 "\tIPv6 multicast: %u\n" 697 "\tIPv6 multicast RA: %u\n" 698 "\tIPv6 multicast NS: %u\n" 699 "\tIPv6 multicast NA: %u\n" 700 "\tICMPv4: %u\n" 701 "\tICMPv6: %u\n" 702 "\tRSSI Breach: %u\n" 703 "\tLow RSSI: %u\n" 704 "\tG-Scan: %u\n" 705 "\tPNO Complete: %u\n" 706 "\tPNO Match: %u\n" 707 "\tUC Drop wake_count: %u\n" 708 "\twake count due to fatal event: %u\n" 709 "\tOEM rsp wake_count: %u\n" 710 "\twake count due to pwr_save_fail_detected: %u\n" 711 "\twake count due to 11d scan: %u\n", 712 unspecified_wake_count, 713 wow_stats.ucast_wake_up_count, 714 wow_stats.bcast_wake_up_count, 715 wow_stats.ipv4_mcast_wake_up_count, 716 wow_stats.ipv6_mcast_wake_up_count, 717 wow_stats.ipv6_mcast_ra_stats, 718 wow_stats.ipv6_mcast_ns_stats, 719 wow_stats.ipv6_mcast_na_stats, 720 wow_stats.icmpv4_count, 721 wow_stats.icmpv6_count, 722 wow_stats.rssi_breach_wake_up_count, 723 wow_stats.low_rssi_wake_up_count, 724 wow_stats.gscan_wake_up_count, 725 wow_stats.pno_complete_wake_up_count, 726 wow_stats.pno_match_wake_up_count, 727 wow_stats.uc_drop_wake_up_count, 728 wow_stats.fatal_event_wake_up_count, 729 wow_stats.oem_response_wake_up_count, 730 wow_stats.pwr_save_fail_detected, 731 wow_stats.scan_11d); 732 733 return QDF_STATUS_SUCCESS; 734 } 735 ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev * vdev,enum stats_req_type type,struct request_info * info)736 QDF_STATUS ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev *vdev, 737 enum stats_req_type type, 738 struct request_info *info) 739 { 740 QDF_STATUS status; 741 742 status = ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev), 743 type, info); 744 if (QDF_IS_STATUS_ERROR(status)) { 745 cp_stats_err("ucfg_mc_cp_stats_set_pending_req pdev failed: %d", 746 status); 747 return status; 748 } 749 750 return tgt_send_mc_cp_stats_req(wlan_vdev_get_psoc(vdev), type, info); 751 } 752 753 #ifdef WLAN_FEATURE_BIG_DATA_STATS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev * vdev,enum stats_req_type type,struct request_info * info)754 QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev, 755 enum stats_req_type type, 756 struct request_info *info) 757 { 758 QDF_STATUS status; 759 760 status = ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev), 761 type, info); 762 if (QDF_IS_STATUS_ERROR(status)) { 763 cp_stats_err("ucfg_mc_cp_stats_set_pending_req pdev failed: %d", 764 status); 765 return status; 766 } 767 return tgt_send_mc_cp_stats_req(wlan_vdev_get_psoc(vdev), type, info); 768 } 769 ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc * psoc,bool enable)770 void ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc *psoc, 771 bool enable) 772 { 773 struct psoc_mc_cp_stats *psoc_mc_stats; 774 struct psoc_cp_stats *psoc_cp_stats_priv; 775 776 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 777 if (!psoc_cp_stats_priv) { 778 cp_stats_err("psoc cp stats object is null"); 779 return; 780 } 781 782 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 783 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 784 psoc_mc_stats->big_data_fw_support_enable = enable; 785 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 786 } 787 ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc * psoc,bool * enable)788 void ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc *psoc, 789 bool *enable) 790 { 791 struct psoc_mc_cp_stats *psoc_mc_stats; 792 struct psoc_cp_stats *psoc_cp_stats_priv; 793 794 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 795 if (!psoc_cp_stats_priv) { 796 cp_stats_err("psoc cp stats object is null"); 797 return; 798 } 799 800 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 801 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 802 *enable = psoc_mc_stats->big_data_fw_support_enable; 803 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 804 } 805 #endif 806 ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev * vdev,int * dbm)807 QDF_STATUS ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, 808 int *dbm) 809 { 810 struct wlan_objmgr_pdev *pdev; 811 struct pdev_mc_cp_stats *pdev_mc_stats; 812 struct pdev_cp_stats *pdev_cp_stats_priv; 813 struct vdev_mc_cp_stats *vdev_mc_stats; 814 struct vdev_cp_stats *vdev_cp_stat; 815 uint32_t vdev_power = 0; 816 817 vdev_cp_stat = wlan_cp_stats_get_vdev_stats_obj(vdev); 818 if (vdev_cp_stat) { 819 wlan_cp_stats_vdev_obj_lock(vdev_cp_stat); 820 vdev_mc_stats = vdev_cp_stat->vdev_stats; 821 vdev_power = vdev_mc_stats->vdev_extd_stats.vdev_tx_power; 822 wlan_cp_stats_vdev_obj_unlock(vdev_cp_stat); 823 if (vdev_power) { 824 *dbm = vdev_power; 825 return QDF_STATUS_SUCCESS; 826 } 827 } 828 829 pdev = wlan_vdev_get_pdev(vdev); 830 pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); 831 if (!pdev_cp_stats_priv) { 832 cp_stats_err("pdev cp stats object is null"); 833 return QDF_STATUS_E_NULL_VALUE; 834 } 835 836 wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); 837 pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; 838 *dbm = pdev_mc_stats->max_pwr; 839 wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); 840 841 return QDF_STATUS_SUCCESS; 842 } 843 ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc * psoc,enum stats_req_type type)844 bool ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc *psoc, 845 enum stats_req_type type) 846 { 847 uint32_t pending_req_map; 848 struct psoc_mc_cp_stats *psoc_mc_stats; 849 struct psoc_cp_stats *psoc_cp_stats_priv; 850 851 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 852 if (!psoc_cp_stats_priv) { 853 cp_stats_err("psoc cp stats object is null"); 854 return false; 855 } 856 857 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 858 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 859 pending_req_map = psoc_mc_stats->pending.type_map; 860 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 861 862 return (pending_req_map & (1 << type)); 863 } 864 ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc * psoc,enum stats_req_type type,struct request_info * req)865 QDF_STATUS ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc *psoc, 866 enum stats_req_type type, 867 struct request_info *req) 868 { 869 struct psoc_mc_cp_stats *psoc_mc_stats; 870 struct psoc_cp_stats *psoc_cp_stats_priv; 871 872 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 873 if (!psoc_cp_stats_priv) { 874 cp_stats_err("psoc cp stats object is null"); 875 return QDF_STATUS_E_NULL_VALUE; 876 } 877 878 if (type >= TYPE_MAX) { 879 cp_stats_err("Invalid type index: %d", type); 880 return QDF_STATUS_E_INVAL; 881 } 882 883 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 884 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 885 if (psoc_mc_stats->is_cp_stats_suspended) { 886 cp_stats_debug("cp stats is suspended try again after resume"); 887 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 888 return QDF_STATUS_E_AGAIN; 889 } 890 psoc_mc_stats->pending.type_map |= (1 << type); 891 psoc_mc_stats->pending.req[type] = *req; 892 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 893 894 return QDF_STATUS_SUCCESS; 895 } 896 ucfg_mc_cp_stats_reset_pending_req(struct wlan_objmgr_psoc * psoc,enum stats_req_type type,struct request_info * last_req,bool * pending)897 QDF_STATUS ucfg_mc_cp_stats_reset_pending_req(struct wlan_objmgr_psoc *psoc, 898 enum stats_req_type type, 899 struct request_info *last_req, 900 bool *pending) 901 { 902 struct psoc_mc_cp_stats *psoc_mc_stats; 903 struct psoc_cp_stats *psoc_cp_stats_priv; 904 905 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 906 if (!psoc_cp_stats_priv) { 907 cp_stats_err("psoc cp stats object is null"); 908 return QDF_STATUS_E_NULL_VALUE; 909 } 910 911 if (type >= TYPE_MAX) { 912 cp_stats_err("Invalid type index: %d", type); 913 return QDF_STATUS_E_INVAL; 914 } 915 916 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 917 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 918 if (psoc_mc_stats->pending.type_map & (1 << type)) { 919 *last_req = psoc_mc_stats->pending.req[type]; 920 *pending = true; 921 } else { 922 *pending = false; 923 } 924 psoc_mc_stats->pending.type_map &= ~(1 << type); 925 qdf_mem_zero(&psoc_mc_stats->pending.req[type], 926 sizeof(psoc_mc_stats->pending.req[type])); 927 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 928 929 return QDF_STATUS_SUCCESS; 930 } 931 ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc * psoc,enum stats_req_type type,struct request_info * info)932 QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc, 933 enum stats_req_type type, 934 struct request_info *info) 935 { 936 struct psoc_mc_cp_stats *psoc_mc_stats; 937 struct psoc_cp_stats *psoc_cp_stats_priv; 938 939 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 940 if (!psoc_cp_stats_priv) { 941 cp_stats_err("psoc cp stats object is null"); 942 return QDF_STATUS_E_NULL_VALUE; 943 } 944 945 if (type >= TYPE_MAX) { 946 cp_stats_err("Invalid type index: %d", type); 947 return QDF_STATUS_E_INVAL; 948 } 949 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 950 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 951 *info = psoc_mc_stats->pending.req[type]; 952 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 953 954 return QDF_STATUS_SUCCESS; 955 } 956 957 /** 958 * ucfg_mc_cp_stats_free_peer_stats_info_ext() - API to free peer stats info ext 959 * structure 960 * @ev: structure from where peer stats info ext needs to be freed 961 * 962 * Return: none 963 */ ucfg_mc_cp_stats_free_peer_stats_info_ext(struct stats_event * ev)964 static void ucfg_mc_cp_stats_free_peer_stats_info_ext(struct stats_event *ev) 965 { 966 struct peer_stats_info_ext_event *peer_stats_info = 967 ev->peer_stats_info_ext; 968 uint16_t i; 969 970 for (i = 0; i < ev->num_peer_stats_info_ext; i++) { 971 qdf_mem_free(peer_stats_info->tx_pkt_per_mcs); 972 qdf_mem_free(peer_stats_info->rx_pkt_per_mcs); 973 peer_stats_info++; 974 } 975 976 qdf_mem_free(ev->peer_stats_info_ext); 977 } 978 ucfg_mc_cp_stats_free_stats_resources(struct stats_event * ev)979 void ucfg_mc_cp_stats_free_stats_resources(struct stats_event *ev) 980 { 981 if (!ev) 982 return; 983 984 qdf_mem_free(ev->pdev_stats); 985 qdf_mem_free(ev->pdev_extd_stats); 986 qdf_mem_free(ev->peer_adv_stats); 987 qdf_mem_free(ev->peer_stats); 988 qdf_mem_free(ev->cca_stats); 989 qdf_mem_free(ev->vdev_summary_stats); 990 qdf_mem_free(ev->vdev_chain_rssi); 991 qdf_mem_free(ev->peer_extended_stats); 992 ucfg_mc_cp_stats_free_peer_stats_info_ext(ev); 993 qdf_mem_free(ev->vdev_extd_stats); 994 qdf_mem_zero(ev, sizeof(*ev)); 995 } 996 ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev * vdev,struct cca_stats * cca_stats)997 QDF_STATUS ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev *vdev, 998 struct cca_stats *cca_stats) 999 { 1000 struct vdev_cp_stats *vdev_cp_stats_priv; 1001 struct vdev_mc_cp_stats *vdev_mc_stats; 1002 1003 vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); 1004 if (!vdev_cp_stats_priv) { 1005 cp_stats_err("vdev cp stats object is null"); 1006 return QDF_STATUS_E_NULL_VALUE; 1007 } 1008 1009 wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); 1010 vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; 1011 cca_stats->congestion = vdev_mc_stats->cca.congestion; 1012 wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); 1013 return QDF_STATUS_SUCCESS; 1014 } 1015 ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev * vdev,uint32_t flags)1016 QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev, 1017 uint32_t flags) 1018 { 1019 struct vdev_mc_cp_stats *vdev_mc_stats; 1020 struct vdev_cp_stats *vdev_cp_stats_priv; 1021 1022 vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); 1023 if (!vdev_cp_stats_priv) { 1024 cp_stats_err("vdev cp stats object is null"); 1025 return QDF_STATUS_E_NULL_VALUE; 1026 } 1027 1028 wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); 1029 vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; 1030 vdev_mc_stats->tx_rate_flags = flags; 1031 wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); 1032 1033 return QDF_STATUS_SUCCESS; 1034 } 1035 ucfg_mc_cp_stats_register_lost_link_info_cb(struct wlan_objmgr_psoc * psoc,void (* lost_link_cp_stats_info_cb)(void * stats_ev))1036 void ucfg_mc_cp_stats_register_lost_link_info_cb( 1037 struct wlan_objmgr_psoc *psoc, 1038 void (*lost_link_cp_stats_info_cb)(void *stats_ev)) 1039 { 1040 struct psoc_cp_stats *psoc_cp_stats_priv; 1041 1042 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 1043 if (!psoc_cp_stats_priv) { 1044 cp_stats_err("psoc cp stats object is null"); 1045 return; 1046 } 1047 1048 psoc_cp_stats_priv->legacy_stats_cb = lost_link_cp_stats_info_cb; 1049 } 1050 1051 #ifdef QCA_SUPPORT_CP_STATS wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,qdf_freq_t req_freq)1052 uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc, 1053 uint8_t vdev_id, qdf_freq_t req_freq) 1054 { 1055 struct wlan_objmgr_pdev *pdev; 1056 struct wlan_objmgr_vdev *vdev; 1057 struct pdev_cp_stats *pdev_cp_stats_priv; 1058 struct per_channel_stats *channel_stats; 1059 struct channel_status *channel_status_list; 1060 uint8_t total_channel, chan_load = 0; 1061 uint8_t i; 1062 uint32_t rx_clear_count = 0, cycle_count = 0; 1063 bool found = false; 1064 1065 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1066 WLAN_CP_STATS_ID); 1067 if (!vdev) 1068 return 0; 1069 1070 pdev = wlan_vdev_get_pdev(vdev); 1071 if (!pdev) { 1072 cp_stats_err("pdev object is null"); 1073 goto release_ref; 1074 } 1075 1076 pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); 1077 if (!pdev_cp_stats_priv) { 1078 cp_stats_err("pdev cp stats object is null"); 1079 goto release_ref; 1080 } 1081 1082 channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; 1083 channel_status_list = channel_stats->channel_status_list; 1084 total_channel = channel_stats->total_channel; 1085 1086 for (i = 0; i < total_channel; i++) { 1087 if (channel_status_list[i].channel_freq == req_freq) { 1088 rx_clear_count = channel_status_list[i].rx_clear_count; 1089 cycle_count = channel_status_list[i].cycle_count; 1090 found = true; 1091 break; 1092 } 1093 } 1094 1095 if (!found) { 1096 cp_stats_debug("no channel found for freq:%d", req_freq); 1097 goto release_ref; 1098 } 1099 1100 if (cycle_count == 0) { 1101 cp_stats_debug("cycle_count is zero"); 1102 goto release_ref; 1103 } 1104 1105 chan_load = ((rx_clear_count * 255) / cycle_count); 1106 1107 cp_stats_debug("t_chan:%d, freq:%d, rcc:%u, cc:%u, chan_load:%d", 1108 total_channel, req_freq, rx_clear_count, cycle_count, 1109 chan_load); 1110 1111 release_ref: 1112 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 1113 return chan_load; 1114 } 1115 #endif 1116 1117 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD 1118 static QDF_STATUS ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc * psoc)1119 ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc *psoc) 1120 { 1121 struct psoc_mc_cp_stats *psoc_mc_stats; 1122 struct psoc_cp_stats *psoc_cp_stats_priv; 1123 1124 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 1125 if (!psoc_cp_stats_priv) { 1126 cp_stats_err("psoc cp stats object is null"); 1127 return QDF_STATUS_E_NULL_VALUE; 1128 } 1129 1130 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 1131 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 1132 psoc_mc_stats->is_cp_stats_suspended = true; 1133 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 1134 1135 return QDF_STATUS_SUCCESS; 1136 } 1137 1138 static QDF_STATUS ucfg_mc_cp_stats_resume_req_handler(struct wlan_objmgr_psoc * psoc)1139 ucfg_mc_cp_stats_resume_req_handler(struct wlan_objmgr_psoc *psoc) 1140 { 1141 struct psoc_mc_cp_stats *psoc_mc_stats; 1142 struct psoc_cp_stats *psoc_cp_stats_priv; 1143 1144 psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); 1145 if (!psoc_cp_stats_priv) { 1146 cp_stats_err("psoc cp stats object is null"); 1147 return QDF_STATUS_E_NULL_VALUE; 1148 } 1149 1150 wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); 1151 psoc_mc_stats = psoc_cp_stats_priv->obj_stats; 1152 psoc_mc_stats->is_cp_stats_suspended = false; 1153 wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); 1154 1155 return QDF_STATUS_SUCCESS; 1156 } 1157 1158 static QDF_STATUS ucfg_mc_cp_stats_resume_handler(struct wlan_objmgr_psoc * psoc,void * arg)1159 ucfg_mc_cp_stats_resume_handler(struct wlan_objmgr_psoc *psoc, 1160 void *arg) 1161 { 1162 return ucfg_mc_cp_stats_resume_req_handler(psoc); 1163 } 1164 1165 static QDF_STATUS ucfg_mc_cp_stats_suspend_handler(struct wlan_objmgr_psoc * psoc,void * arg)1166 ucfg_mc_cp_stats_suspend_handler(struct wlan_objmgr_psoc *psoc, 1167 void *arg) 1168 { 1169 return ucfg_mc_cp_stats_suspend_req_handler(psoc); 1170 } 1171 ucfg_mc_cp_stats_register_pmo_handler(void)1172 void ucfg_mc_cp_stats_register_pmo_handler(void) 1173 { 1174 pmo_register_suspend_handler(WLAN_UMAC_COMP_CP_STATS, 1175 ucfg_mc_cp_stats_suspend_handler, NULL); 1176 pmo_register_resume_handler(WLAN_UMAC_COMP_CP_STATS, 1177 ucfg_mc_cp_stats_resume_handler, NULL); 1178 } 1179 1180 /** 1181 * wlan_cp_stats_get_ch_width_from_chan_info - get ch_width as per num channel 1182 * present in scan event 1183 * @channel_stat: struct scan_chan_info 1184 * 1185 * Return: phy_ch_width. 1186 */ 1187 static enum phy_ch_width wlan_cp_stats_get_ch_width_from_chan_info(struct channel_status * channel_stat)1188 wlan_cp_stats_get_ch_width_from_chan_info(struct channel_status *channel_stat) 1189 { 1190 enum phy_ch_width scanned_ch_width; 1191 1192 switch (channel_stat->subband_info.num_chan) { 1193 case 1: 1194 scanned_ch_width = CH_WIDTH_20MHZ; 1195 break; 1196 case 2: 1197 scanned_ch_width = CH_WIDTH_40MHZ; 1198 break; 1199 case 4: 1200 scanned_ch_width = CH_WIDTH_80MHZ; 1201 break; 1202 case 8: 1203 scanned_ch_width = CH_WIDTH_160MHZ; 1204 break; 1205 default: 1206 scanned_ch_width = CH_WIDTH_INVALID; 1207 break; 1208 } 1209 1210 return scanned_ch_width; 1211 } 1212 1213 /** 1214 * wlan_cp_stats_update_per_channel_stats - update per channel stats as per 1215 * data present in scan event 1216 * @channel_stats: per channel stats 1217 * @ev_channel_stat: channel stats per scan event 1218 * @freq: freq to update channel stats 1219 * @rx_clear_count: rx clear count for a freq 1220 * 1221 * Return: none. 1222 */ 1223 static void wlan_cp_stats_update_per_channel_stats(struct per_channel_stats * channel_stats,struct channel_status * ev_channel_stat,uint32_t freq,uint32_t rx_clear_count)1224 wlan_cp_stats_update_per_channel_stats(struct per_channel_stats *channel_stats, 1225 struct channel_status *ev_channel_stat, 1226 uint32_t freq, uint32_t rx_clear_count) 1227 { 1228 struct channel_status *channel_status_list; 1229 uint8_t total_channel, i; 1230 bool found = false; 1231 1232 channel_status_list = channel_stats->channel_status_list; 1233 total_channel = channel_stats->total_channel; 1234 1235 for (i = 0; i < total_channel; i++) { 1236 if (channel_status_list[i].channel_freq == freq) { 1237 cp_stats_debug("update rcc: %d, cc:%d at index: %d, freq: %d", 1238 ev_channel_stat->rx_clear_count, 1239 ev_channel_stat->cycle_count, i, freq); 1240 1241 channel_status_list[i].rx_clear_count = rx_clear_count; 1242 channel_status_list[i].cycle_count = 1243 ev_channel_stat->cycle_count; 1244 found = true; 1245 break; 1246 } 1247 } 1248 1249 if (!found) { 1250 if (total_channel < NUM_CHANNELS) { 1251 ev_channel_stat->rx_clear_count = rx_clear_count; 1252 ev_channel_stat->channel_freq = freq; 1253 1254 cp_stats_debug("Add rcc: %d cc: %d, at index: %d, freq: %d", 1255 ev_channel_stat->rx_clear_count, 1256 ev_channel_stat->rx_clear_count, 1257 total_channel, freq); 1258 1259 qdf_mem_copy(&channel_status_list[total_channel++], 1260 ev_channel_stat, 1261 sizeof(*channel_status_list)); 1262 channel_stats->total_channel = total_channel; 1263 } else { 1264 cp_stats_debug("Chan cnt exceed, channel_id: %d", 1265 ev_channel_stat->channel_id); 1266 } 1267 } 1268 } 1269 1270 /** 1271 * wlan_cp_stats_update_channel_stats - wrapper api to update per channel stats 1272 * as per data present in scan event 1273 * @channel_stats: per channel stats 1274 * @ev_channel_stat: channel stats per scan event 1275 * 1276 * Return: none. 1277 */ 1278 static void wlan_cp_stats_update_channel_stats(struct per_channel_stats * channel_stats,struct channel_status * ev_channel_stat)1279 wlan_cp_stats_update_channel_stats(struct per_channel_stats *channel_stats, 1280 struct channel_status *ev_channel_stat) 1281 { 1282 uint8_t index, freq_info_num; 1283 enum phy_ch_width scanned_ch_width; 1284 const struct bonded_channel_freq *range = NULL; 1285 uint16_t start_freq, end_freq; 1286 uint32_t rx_clear_count; 1287 1288 scanned_ch_width = 1289 wlan_cp_stats_get_ch_width_from_chan_info(ev_channel_stat); 1290 if (scanned_ch_width == CH_WIDTH_INVALID) { 1291 cp_stats_debug("Invalid scanned_ch_width"); 1292 return; 1293 } 1294 1295 if (scanned_ch_width == CH_WIDTH_20MHZ) { 1296 start_freq = ev_channel_stat->channel_freq; 1297 end_freq = ev_channel_stat->channel_freq; 1298 } else { 1299 range = 1300 wlan_reg_get_bonded_chan_entry(ev_channel_stat->channel_freq, 1301 scanned_ch_width, 0); 1302 if (!range) { 1303 cp_stats_debug("range is NULL for freq %d, ch_width %d", 1304 ev_channel_stat->channel_freq, 1305 scanned_ch_width); 1306 return; 1307 } 1308 start_freq = range->start_freq; 1309 end_freq = range->end_freq; 1310 } 1311 1312 freq_info_num = ev_channel_stat->subband_info.num_chan; 1313 index = 0; 1314 1315 cp_stats_debug("freq :%d bw %d, range [%d-%d], num_freq:%d", 1316 ev_channel_stat->channel_freq, scanned_ch_width, 1317 start_freq, end_freq, freq_info_num); 1318 1319 for (; start_freq <= end_freq;) { 1320 if (index >= freq_info_num || index >= MAX_WIDE_BAND_SCAN_CHAN) 1321 break; 1322 rx_clear_count = 1323 ev_channel_stat->subband_info.cca_busy_subband_info[index]; 1324 wlan_cp_stats_update_per_channel_stats(channel_stats, 1325 ev_channel_stat, 1326 start_freq, 1327 rx_clear_count); 1328 1329 start_freq += BW_20_MHZ; 1330 index++; 1331 } 1332 } 1333 wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc * psoc,struct channel_status * ev_channel_stat,uint8_t vdev_id)1334 void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc, 1335 struct channel_status *ev_channel_stat, 1336 uint8_t vdev_id) 1337 { 1338 struct wlan_objmgr_pdev *pdev; 1339 struct wlan_objmgr_vdev *vdev; 1340 struct pdev_cp_stats *pdev_cp_stats_priv; 1341 struct per_channel_stats *channel_stats; 1342 struct channel_status *channel_status_list; 1343 uint8_t total_channel; 1344 uint8_t i; 1345 bool found = false; 1346 1347 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1348 WLAN_CP_STATS_ID); 1349 if (!vdev) 1350 return; 1351 1352 pdev = wlan_vdev_get_pdev(vdev); 1353 if (!pdev) { 1354 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 1355 cp_stats_err("pdev object is null"); 1356 return; 1357 } 1358 1359 pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); 1360 if (!pdev_cp_stats_priv) { 1361 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 1362 cp_stats_err("pdev cp stats object is null"); 1363 return; 1364 } 1365 1366 channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; 1367 channel_status_list = channel_stats->channel_status_list; 1368 total_channel = channel_stats->total_channel; 1369 1370 if (ev_channel_stat->subband_info.is_wide_band_scan) { 1371 wlan_cp_stats_update_channel_stats(channel_stats, 1372 ev_channel_stat); 1373 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 1374 return; 1375 } 1376 1377 for (i = 0; i < total_channel; i++) { 1378 if (channel_status_list[i].channel_id == 1379 ev_channel_stat->channel_id) { 1380 if (ev_channel_stat->cmd_flags == 1381 WMI_CHAN_InFO_END_RESP && 1382 channel_status_list[i].cmd_flags == 1383 WMI_CHAN_InFO_START_RESP) { 1384 /* adjust to delta value for counts */ 1385 ev_channel_stat->rx_clear_count -= 1386 channel_status_list[i].rx_clear_count; 1387 ev_channel_stat->cycle_count -= 1388 channel_status_list[i].cycle_count; 1389 ev_channel_stat->rx_frame_count -= 1390 channel_status_list[i].rx_frame_count; 1391 ev_channel_stat->tx_frame_count -= 1392 channel_status_list[i].tx_frame_count; 1393 ev_channel_stat->bss_rx_cycle_count -= 1394 channel_status_list[i].bss_rx_cycle_count; 1395 } 1396 qdf_mem_copy(&channel_status_list[i], ev_channel_stat, 1397 sizeof(*channel_status_list)); 1398 found = true; 1399 break; 1400 } 1401 } 1402 1403 if (!found) { 1404 if (total_channel < NUM_CHANNELS) { 1405 qdf_mem_copy(&channel_status_list[total_channel++], 1406 ev_channel_stat, 1407 sizeof(*channel_status_list)); 1408 channel_stats->total_channel = total_channel; 1409 } else { 1410 cp_stats_err("Chan cnt exceed, channel_id=%d", 1411 ev_channel_stat->channel_id); 1412 } 1413 } 1414 1415 wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); 1416 } 1417 1418 struct channel_status * ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev * pdev,uint32_t chan_freq)1419 ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev *pdev, 1420 uint32_t chan_freq) 1421 { 1422 struct pdev_cp_stats *pdev_cp_stats_priv; 1423 struct per_channel_stats *channel_stats; 1424 struct channel_status *entry; 1425 uint8_t i; 1426 1427 pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); 1428 if (!pdev_cp_stats_priv) { 1429 cp_stats_err("pdev cp stats object is null"); 1430 return NULL; 1431 } 1432 1433 channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; 1434 1435 for (i = 0; i < channel_stats->total_channel; i++) { 1436 entry = &channel_stats->channel_status_list[i]; 1437 if (entry->channel_freq == chan_freq) 1438 return entry; 1439 } 1440 cp_stats_err("Channel %d status info not exist", chan_freq); 1441 1442 return NULL; 1443 } 1444 ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev * pdev)1445 void ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev *pdev) 1446 { 1447 struct pdev_cp_stats *pdev_cp_stats_priv; 1448 struct per_channel_stats *channel_stats; 1449 1450 pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); 1451 if (!pdev_cp_stats_priv) { 1452 cp_stats_err("pdev cp stats object is null"); 1453 return; 1454 } 1455 1456 channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; 1457 channel_stats->total_channel = 0; 1458 } 1459 1460 #endif 1461