1 /* 2 * Copyright (c) 2019-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 #include <cfr_defs_i.h> 21 #include <qdf_types.h> 22 #include <wlan_objmgr_pdev_obj.h> 23 #include <wlan_objmgr_vdev_obj.h> 24 #include <wlan_objmgr_peer_obj.h> 25 #include <wlan_cfr_tgt_api.h> 26 #include <qdf_streamfs.h> 27 #include <target_if.h> 28 #include <target_if_direct_buf_rx_api.h> 29 #include <wlan_osif_priv.h> 30 #include <cfg_ucfg_api.h> 31 #include "cfr_cfg.h" 32 #ifdef WLAN_CFR_PM 33 #include "host_diag_core_event.h" 34 #endif 35 36 /** 37 * wlan_cfr_is_ini_disabled() - Check if cfr feature is disabled 38 * @pdev: the physical device object. 39 * 40 * Return : true if cfr is disabled, else false. 41 */ 42 static bool wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev * pdev)43 wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev *pdev) 44 { 45 struct wlan_objmgr_psoc *psoc; 46 uint8_t cfr_disable_bitmap; 47 48 psoc = wlan_pdev_get_psoc(pdev); 49 if (!psoc) { 50 cfr_err("psoc is null"); 51 return true; 52 } 53 54 cfr_disable_bitmap = cfg_get(psoc, CFG_CFR_DISABLE); 55 56 if (cfr_disable_bitmap & (1 << wlan_objmgr_pdev_get_pdev_id(pdev))) { 57 cfr_info("cfr is disabled for pdev[%d]", 58 wlan_objmgr_pdev_get_pdev_id(pdev)); 59 return true; 60 } 61 62 return false; 63 } 64 65 /** 66 * wlan_cfr_get_dbr_num_entries() - Get entry number of DBR ring 67 * @pdev: the physical device object. 68 * 69 * Return : Entry number of DBR ring. 70 */ 71 static uint32_t wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev * pdev)72 wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev *pdev) 73 { 74 struct wlan_objmgr_psoc *psoc; 75 struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap; 76 uint8_t num_dbr_ring_caps, cap_idx, pdev_id; 77 struct target_psoc_info *tgt_psoc_info; 78 uint32_t num_entries = MAX_LUT_ENTRIES; 79 80 if (!pdev) { 81 cfr_err("Invalid pdev"); 82 return num_entries; 83 } 84 85 psoc = wlan_pdev_get_psoc(pdev); 86 if (!psoc) { 87 cfr_err("psoc is null"); 88 return num_entries; 89 } 90 91 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 92 if (!tgt_psoc_info) { 93 cfr_err("target_psoc_info is null"); 94 return num_entries; 95 } 96 97 num_dbr_ring_caps = target_psoc_get_num_dbr_ring_caps(tgt_psoc_info); 98 dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info); 99 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 100 101 for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) { 102 if (dbr_ring_cap[cap_idx].pdev_id == pdev_id && 103 dbr_ring_cap[cap_idx].mod_id == DBR_MODULE_CFR) 104 num_entries = dbr_ring_cap[cap_idx].ring_elems_min; 105 } 106 107 num_entries = QDF_MIN(num_entries, MAX_LUT_ENTRIES); 108 cfr_debug("pdev id %d, num_entries %d", pdev_id, num_entries); 109 110 return num_entries; 111 } 112 113 #ifdef WLAN_CFR_PM 114 /** 115 * cfr_wakelock_init(): Create/init wake lock for CFR 116 * @pcfr: CFR pdev context 117 * 118 * Create/init wake lock for CFR 119 * 120 * Return None 121 */ cfr_wakelock_init(struct pdev_cfr * pcfr)122 static void cfr_wakelock_init(struct pdev_cfr *pcfr) 123 { 124 if (!pcfr) { 125 cfr_debug("NULL pa"); 126 return; 127 } 128 129 pcfr->is_prevent_suspend = false; 130 qdf_wake_lock_create(&pcfr->wake_lock, "wlan_cfr"); 131 qdf_runtime_lock_init(&pcfr->runtime_lock); 132 } 133 134 /** 135 * cfr_wakelock_deinit(): Destroy/deinit wake lock for CFR 136 * @pcfr: CFR pdev context 137 * 138 * Destroy/deinit wake lock for CFR 139 * 140 * Return None 141 */ cfr_wakelock_deinit(struct pdev_cfr * pcfr)142 static void cfr_wakelock_deinit(struct pdev_cfr *pcfr) 143 { 144 if (!pcfr) { 145 cfr_debug("NULL pa"); 146 return; 147 } 148 149 qdf_runtime_lock_deinit(&pcfr->runtime_lock); 150 qdf_wake_lock_destroy(&pcfr->wake_lock); 151 } 152 #else cfr_wakelock_init(struct pdev_cfr * pcfr)153 static inline void cfr_wakelock_init(struct pdev_cfr *pcfr) 154 { 155 } 156 cfr_wakelock_deinit(struct pdev_cfr * pcfr)157 static inline void cfr_wakelock_deinit(struct pdev_cfr *pcfr) 158 { 159 } 160 #endif 161 162 QDF_STATUS wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc * psoc,void * arg)163 wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg) 164 { 165 struct psoc_cfr *cfr_sc = NULL; 166 167 cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr)); 168 if (!cfr_sc) { 169 cfr_err("Failed to allocate cfr_ctx object\n"); 170 return QDF_STATUS_E_NOMEM; 171 } 172 173 cfr_sc->psoc_obj = psoc; 174 175 wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR, 176 (void *)cfr_sc, 177 QDF_STATUS_SUCCESS); 178 179 return QDF_STATUS_SUCCESS; 180 } 181 182 QDF_STATUS wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc * psoc,void * arg)183 wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg) 184 { 185 struct psoc_cfr *cfr_sc = NULL; 186 187 cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc, 188 WLAN_UMAC_COMP_CFR); 189 if (cfr_sc) { 190 wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR, 191 (void *)cfr_sc); 192 qdf_mem_free(cfr_sc); 193 } 194 195 return QDF_STATUS_SUCCESS; 196 } 197 198 #ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT wlan_cfr_get_aoa_caps(struct pdev_cfr * pa)199 static QDF_STATUS wlan_cfr_get_aoa_caps(struct pdev_cfr *pa) 200 { 201 struct wlan_objmgr_pdev *pdev = pa->pdev_obj; 202 struct wlan_objmgr_psoc *psoc; 203 struct target_psoc_info *tgt_psoc_info; 204 struct wlan_psoc_host_rcc_enh_aoa_caps_ext2 *aoa_caps; 205 uint32_t i, max_agc_gain_tbl_sz; 206 207 if (!pdev) { 208 cfr_err("Invalid pdev"); 209 return QDF_STATUS_E_INVAL; 210 } 211 212 psoc = wlan_pdev_get_psoc(pdev); 213 if (!psoc) { 214 cfr_err("psoc is null"); 215 return QDF_STATUS_E_INVAL; 216 } 217 218 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 219 if (!tgt_psoc_info) { 220 cfr_err("target_psoc_info is null"); 221 return QDF_STATUS_E_INVAL; 222 } 223 224 pa->is_enh_aoa_data = false; 225 226 aoa_caps = target_psoc_get_aoa_caps(tgt_psoc_info); 227 228 if (!aoa_caps) { 229 cfr_info("NO enhanced AoA cap advertised"); 230 return QDF_STATUS_SUCCESS; 231 } 232 233 max_agc_gain_tbl_sz = sizeof(uint16_t) * PSOC_MAX_NUM_AGC_GAIN_TBLS; 234 pa->max_entries_all_table = 0; 235 pa->max_agc_gain_tbls = aoa_caps->max_agc_gain_tbls; 236 237 if (pa->max_agc_gain_tbls > PSOC_MAX_NUM_AGC_GAIN_TBLS) { 238 cfr_err("Invalid num of tables advertised"); 239 return QDF_STATUS_E_INVAL; 240 } 241 242 qdf_mem_copy(pa->max_agc_gain_per_tbl_2g, 243 aoa_caps->max_agc_gain_per_tbl_2g, 244 max_agc_gain_tbl_sz); 245 qdf_mem_copy(pa->max_agc_gain_per_tbl_5g, 246 aoa_caps->max_agc_gain_per_tbl_5g, 247 max_agc_gain_tbl_sz); 248 qdf_mem_copy(pa->max_agc_gain_per_tbl_6g, 249 aoa_caps->max_agc_gain_per_tbl_6g, 250 max_agc_gain_tbl_sz); 251 qdf_mem_copy(pa->max_bdf_entries_per_tbl, 252 aoa_caps->max_bdf_entries_per_tbl, 253 (sizeof(uint8_t) * PSOC_MAX_NUM_AGC_GAIN_TBLS)); 254 255 /* table 0's data always starts at offset 0 */ 256 pa->start_ent[0] = 0; 257 for (i = 0; i < pa->max_agc_gain_tbls; i++) { 258 pa->max_entries_all_table += 259 pa->max_bdf_entries_per_tbl[i]; 260 if ((i + 1) < pa->max_agc_gain_tbls) { 261 pa->start_ent[i + 1] = (pa->max_bdf_entries_per_tbl[i] + 262 pa->start_ent[i]); 263 } 264 } 265 266 pa->gain_stop_index_array = qdf_mem_malloc(sizeof(uint16_t) * 267 pa->max_entries_all_table * 268 HOST_MAX_CHAINS); 269 if (!pa->gain_stop_index_array) { 270 qdf_err("Failed to allocate gain stop array"); 271 return QDF_STATUS_E_NOMEM; 272 } 273 274 pa->enh_phase_delta_array = qdf_mem_malloc(sizeof(uint16_t) * 275 pa->max_entries_all_table * 276 HOST_MAX_CHAINS); 277 if (!pa->enh_phase_delta_array) { 278 qdf_err("Failed to allocate phase delta array"); 279 qdf_mem_free(pa->gain_stop_index_array); 280 return QDF_STATUS_E_NOMEM; 281 } 282 283 pa->is_enh_aoa_data = true; 284 285 return QDF_STATUS_SUCCESS; 286 } 287 #else wlan_cfr_get_aoa_caps(struct pdev_cfr * pa)288 static QDF_STATUS wlan_cfr_get_aoa_caps(struct pdev_cfr *pa) 289 { 290 return QDF_STATUS_SUCCESS; 291 } 292 #endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */ 293 294 QDF_STATUS wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev * pdev,void * arg)295 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg) 296 { 297 struct pdev_cfr *pa = NULL; 298 uint32_t idx; 299 QDF_STATUS status; 300 301 if (!pdev) { 302 cfr_err("PDEV is NULL\n"); 303 return QDF_STATUS_E_FAILURE; 304 } 305 306 if (wlan_cfr_is_ini_disabled(pdev)) { 307 wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN); 308 return QDF_STATUS_E_NOSUPPORT; 309 } 310 311 wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN); 312 313 pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr)); 314 if (!pa) { 315 cfr_err("Failed to allocate pdev_cfr object\n"); 316 return QDF_STATUS_E_NOMEM; 317 } 318 pa->pdev_obj = pdev; 319 pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev); 320 if (!pa->lut_num) { 321 cfr_err("lut num is 0"); 322 qdf_mem_free(pa); 323 return QDF_STATUS_E_INVAL; 324 } 325 pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num * 326 sizeof(struct look_up_table *)); 327 if (!pa->lut) { 328 cfr_err("Failed to allocate lut, lut num %d", pa->lut_num); 329 qdf_mem_free(pa); 330 return QDF_STATUS_E_NOMEM; 331 } 332 for (idx = 0; idx < pa->lut_num; idx++) 333 pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc( 334 sizeof(struct look_up_table)); 335 336 /* Allocate AoA related variables here based on FW capability */ 337 status = wlan_cfr_get_aoa_caps(pa); 338 if (QDF_IS_STATUS_ERROR(status)) { 339 cfr_err("Failed to get aoa caps"); 340 for (idx = 0; idx < pa->lut_num; idx++) 341 qdf_mem_free(pa->lut[idx]); 342 qdf_mem_free(pa); 343 return status; 344 } 345 346 cfr_wakelock_init(pa); 347 wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR, 348 (void *)pa, QDF_STATUS_SUCCESS); 349 350 return QDF_STATUS_SUCCESS; 351 } 352 353 #ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT 354 static inline wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr * pa)355 void wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr *pa) 356 { 357 /** 358 * Free enahced AoA related allocations here. 359 * Caller of this API should ensure pa is not NULL 360 */ 361 if (pa->gain_stop_index_array) 362 qdf_mem_free(pa->gain_stop_index_array); 363 364 if (pa->enh_phase_delta_array) 365 qdf_mem_free(pa->enh_phase_delta_array); 366 } 367 #else 368 static inline wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr * pa)369 void wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr *pa) 370 { 371 } 372 #endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */ 373 374 QDF_STATUS wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev * pdev,void * arg)375 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg) 376 { 377 struct pdev_cfr *pa = NULL; 378 uint32_t idx; 379 380 if (!pdev) { 381 cfr_err("PDEV is NULL\n"); 382 return QDF_STATUS_E_FAILURE; 383 } 384 385 if (wlan_cfr_is_feature_disabled(pdev)) { 386 cfr_info("cfr is disabled"); 387 return QDF_STATUS_E_NOSUPPORT; 388 } 389 390 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 391 if (pa) { 392 cfr_wakelock_deinit(pa); 393 wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR, 394 (void *)pa); 395 if (pa->lut) { 396 for (idx = 0; idx < pa->lut_num; idx++) 397 qdf_mem_free(pa->lut[idx]); 398 qdf_mem_free(pa->lut); 399 } 400 401 wlan_cfr_cleanup_enhanced_aoa(pa); 402 qdf_mem_free(pa); 403 } 404 405 return QDF_STATUS_SUCCESS; 406 } 407 408 QDF_STATUS wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer * peer,void * arg)409 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg) 410 { 411 struct peer_cfr *pe = NULL; 412 struct wlan_objmgr_vdev *vdev; 413 struct wlan_objmgr_pdev *pdev = NULL; 414 415 if (!peer) { 416 cfr_err("PEER is NULL\n"); 417 return QDF_STATUS_E_FAILURE; 418 } 419 420 vdev = wlan_peer_get_vdev(peer); 421 if (vdev) 422 pdev = wlan_vdev_get_pdev(vdev); 423 424 if (!pdev) { 425 cfr_err("PDEV is NULL\n"); 426 return QDF_STATUS_E_FAILURE; 427 } 428 429 if (wlan_cfr_is_feature_disabled(pdev)) { 430 cfr_debug("cfr is disabled"); 431 return QDF_STATUS_E_NOSUPPORT; 432 } 433 434 pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr)); 435 if (!pe) { 436 cfr_err("Failed to allocate peer_cfr object\n"); 437 return QDF_STATUS_E_FAILURE; 438 } 439 440 pe->peer_obj = peer; 441 442 /* Remaining will be populated when we give CFR capture command */ 443 wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR, 444 (void *)pe, QDF_STATUS_SUCCESS); 445 return QDF_STATUS_SUCCESS; 446 } 447 448 QDF_STATUS wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer * peer,void * arg)449 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg) 450 { 451 struct peer_cfr *pe = NULL; 452 struct wlan_objmgr_vdev *vdev; 453 struct wlan_objmgr_pdev *pdev = NULL; 454 struct pdev_cfr *pa = NULL; 455 456 if (!peer) { 457 cfr_err("PEER is NULL\n"); 458 return QDF_STATUS_E_FAILURE; 459 } 460 461 vdev = wlan_peer_get_vdev(peer); 462 if (vdev) 463 pdev = wlan_vdev_get_pdev(vdev); 464 465 if (wlan_cfr_is_feature_disabled(pdev)) { 466 cfr_info("cfr is disabled"); 467 return QDF_STATUS_E_NOSUPPORT; 468 } 469 470 if (pdev) 471 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, 472 WLAN_UMAC_COMP_CFR); 473 474 pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); 475 476 if (pa && pe) { 477 if (pe->period && pe->request) 478 pa->cfr_current_sta_count--; 479 } 480 481 if (pe) { 482 wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR, 483 (void *)pe); 484 qdf_mem_free(pe); 485 } 486 487 return QDF_STATUS_SUCCESS; 488 } 489 490 #ifdef CFR_USE_FIXED_FOLDER cfr_get_dev_name(struct wlan_objmgr_pdev * pdev)491 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev) 492 { 493 char *default_name = "wlan"; 494 495 return default_name; 496 } 497 #else 498 /** 499 * cfr_get_dev_name() - Get net device name from pdev 500 * @pdev: objmgr pdev 501 * 502 * Return: netdev name 503 */ cfr_get_dev_name(struct wlan_objmgr_pdev * pdev)504 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev) 505 { 506 struct pdev_osif_priv *pdev_ospriv; 507 struct qdf_net_if *nif; 508 509 pdev_ospriv = wlan_pdev_get_ospriv(pdev); 510 if (!pdev_ospriv) { 511 cfr_err("pdev_ospriv is NULL\n"); 512 return NULL; 513 } 514 515 nif = pdev_ospriv->nif; 516 if (!nif) { 517 cfr_err("pdev nif is NULL\n"); 518 return NULL; 519 } 520 521 return qdf_net_if_get_devname(nif); 522 } 523 #endif 524 cfr_streamfs_init(struct wlan_objmgr_pdev * pdev)525 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev) 526 { 527 struct pdev_cfr *pa = NULL; 528 char *devname; 529 char folder[32]; 530 531 if (!pdev) { 532 cfr_err("PDEV is NULL\n"); 533 return QDF_STATUS_E_FAILURE; 534 } 535 536 if (wlan_cfr_is_feature_disabled(pdev)) { 537 cfr_info("cfr is disabled"); 538 return QDF_STATUS_COMP_DISABLED; 539 } 540 541 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 542 543 if (pa == NULL) { 544 cfr_err("pdev_cfr is NULL\n"); 545 return QDF_STATUS_E_FAILURE; 546 } 547 548 if (!pa->is_cfr_capable) { 549 cfr_err("CFR IS NOT SUPPORTED\n"); 550 return QDF_STATUS_E_FAILURE; 551 } 552 553 devname = cfr_get_dev_name(pdev); 554 if (!devname) { 555 cfr_err("devname is NULL\n"); 556 return QDF_STATUS_E_FAILURE; 557 } 558 559 snprintf(folder, sizeof(folder), "cfr%s", devname); 560 561 pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL); 562 563 if (!pa->dir_ptr) { 564 cfr_err("Directory create failed"); 565 return QDF_STATUS_E_FAILURE; 566 } 567 568 pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr, 569 pa->subbuf_size, 570 pa->num_subbufs, NULL); 571 572 if (!pa->chan_ptr) { 573 cfr_err("Chan create failed"); 574 qdf_streamfs_remove_dir_recursive(pa->dir_ptr); 575 pa->dir_ptr = NULL; 576 return QDF_STATUS_E_FAILURE; 577 } 578 579 return QDF_STATUS_SUCCESS; 580 } 581 cfr_streamfs_remove(struct wlan_objmgr_pdev * pdev)582 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev) 583 { 584 struct pdev_cfr *pa = NULL; 585 586 if (wlan_cfr_is_feature_disabled(pdev)) { 587 cfr_info("cfr is disabled"); 588 return QDF_STATUS_COMP_DISABLED; 589 } 590 591 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 592 if (pa) { 593 if (pa->chan_ptr) { 594 qdf_streamfs_close(pa->chan_ptr); 595 pa->chan_ptr = NULL; 596 } 597 598 if (pa->dir_ptr) { 599 qdf_streamfs_remove_dir_recursive(pa->dir_ptr); 600 pa->dir_ptr = NULL; 601 } 602 603 } else 604 return QDF_STATUS_E_FAILURE; 605 606 return QDF_STATUS_SUCCESS; 607 } 608 cfr_streamfs_write(struct pdev_cfr * pa,const void * write_data,size_t write_len)609 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data, 610 size_t write_len) 611 { 612 if (pa->chan_ptr) { 613 /* write to channel buffer */ 614 qdf_streamfs_write(pa->chan_ptr, (const void *)write_data, 615 write_len); 616 } else 617 return QDF_STATUS_E_FAILURE; 618 619 return QDF_STATUS_SUCCESS; 620 } 621 cfr_streamfs_flush(struct pdev_cfr * pa)622 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa) 623 { 624 if (pa->chan_ptr) { 625 626 /* Flush the data write to channel buffer */ 627 qdf_streamfs_flush(pa->chan_ptr); 628 } else 629 return QDF_STATUS_E_FAILURE; 630 631 return QDF_STATUS_SUCCESS; 632 } 633 cfr_stop_indication(struct wlan_objmgr_vdev * vdev)634 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev) 635 { 636 struct pdev_cfr *pa; 637 uint32_t status; 638 struct wlan_objmgr_pdev *pdev; 639 640 pdev = wlan_vdev_get_pdev(vdev); 641 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 642 if (!pa) { 643 cfr_err("pdev_cfr is NULL\n"); 644 return QDF_STATUS_E_INVAL; 645 } 646 647 /* Don't write stop string if there is valid cfr_nl_cb. Since 648 * userspace needn't stop event string 649 */ 650 if (pa->nl_cb.cfr_nl_cb) 651 return QDF_STATUS_SUCCESS; 652 653 status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR, 654 sizeof(CFR_STOP_STR)); 655 656 status = cfr_streamfs_flush(pa); 657 cfr_debug("stop indication done"); 658 659 return status; 660 } 661 662 #ifdef WLAN_CFR_PM cfr_prevent_suspend(struct pdev_cfr * pcfr)663 QDF_STATUS cfr_prevent_suspend(struct pdev_cfr *pcfr) 664 { 665 if (!pcfr) { 666 cfr_debug("NULL pcfr"); 667 return QDF_STATUS_E_INVAL; 668 } 669 670 if (pcfr->is_prevent_suspend) { 671 cfr_debug("acquired wake lock"); 672 return QDF_STATUS_E_AGAIN; 673 } 674 qdf_wake_lock_acquire(&pcfr->wake_lock, 675 WIFI_POWER_EVENT_WAKELOCK_CFR); 676 qdf_runtime_pm_prevent_suspend(&pcfr->runtime_lock); 677 pcfr->is_prevent_suspend = true; 678 679 return QDF_STATUS_SUCCESS; 680 } 681 cfr_allow_suspend(struct pdev_cfr * pcfr)682 QDF_STATUS cfr_allow_suspend(struct pdev_cfr *pcfr) 683 { 684 if (!pcfr) { 685 cfr_debug("NULL pcfr"); 686 return QDF_STATUS_E_INVAL; 687 } 688 689 if (!pcfr->is_prevent_suspend) { 690 cfr_debug("wake lock not acquired"); 691 return QDF_STATUS_E_INVAL; 692 } 693 qdf_wake_lock_release(&pcfr->wake_lock, 694 WIFI_POWER_EVENT_WAKELOCK_CFR); 695 qdf_runtime_pm_allow_suspend(&pcfr->runtime_lock); 696 pcfr->is_prevent_suspend = false; 697 698 return QDF_STATUS_SUCCESS; 699 } 700 #endif 701