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 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 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 */ 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 */ 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 153 static inline void cfr_wakelock_init(struct pdev_cfr *pcfr) 154 { 155 } 156 157 static inline void cfr_wakelock_deinit(struct pdev_cfr *pcfr) 158 { 159 } 160 #endif 161 162 QDF_STATUS 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 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 QDF_STATUS 199 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg) 200 { 201 struct pdev_cfr *pa = NULL; 202 uint32_t idx; 203 204 if (!pdev) { 205 cfr_err("PDEV is NULL\n"); 206 return QDF_STATUS_E_FAILURE; 207 } 208 209 if (wlan_cfr_is_ini_disabled(pdev)) { 210 wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN); 211 return QDF_STATUS_E_NOSUPPORT; 212 } 213 214 wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN); 215 216 pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr)); 217 if (!pa) { 218 cfr_err("Failed to allocate pdev_cfr object\n"); 219 return QDF_STATUS_E_NOMEM; 220 } 221 pa->pdev_obj = pdev; 222 pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev); 223 if (!pa->lut_num) { 224 cfr_err("lut num is 0"); 225 qdf_mem_free(pa); 226 return QDF_STATUS_E_INVAL; 227 } 228 pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num * 229 sizeof(struct look_up_table *)); 230 if (!pa->lut) { 231 cfr_err("Failed to allocate lut, lut num %d", pa->lut_num); 232 qdf_mem_free(pa); 233 return QDF_STATUS_E_NOMEM; 234 } 235 for (idx = 0; idx < pa->lut_num; idx++) 236 pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc( 237 sizeof(struct look_up_table)); 238 239 cfr_wakelock_init(pa); 240 wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR, 241 (void *)pa, QDF_STATUS_SUCCESS); 242 243 return QDF_STATUS_SUCCESS; 244 } 245 246 QDF_STATUS 247 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg) 248 { 249 struct pdev_cfr *pa = NULL; 250 uint32_t idx; 251 252 if (!pdev) { 253 cfr_err("PDEV is NULL\n"); 254 return QDF_STATUS_E_FAILURE; 255 } 256 257 if (wlan_cfr_is_feature_disabled(pdev)) { 258 cfr_info("cfr is disabled"); 259 return QDF_STATUS_E_NOSUPPORT; 260 } 261 262 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 263 if (pa) { 264 cfr_wakelock_deinit(pa); 265 wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR, 266 (void *)pa); 267 if (pa->lut) { 268 for (idx = 0; idx < pa->lut_num; idx++) 269 qdf_mem_free(pa->lut[idx]); 270 qdf_mem_free(pa->lut); 271 } 272 qdf_mem_free(pa); 273 } 274 275 return QDF_STATUS_SUCCESS; 276 } 277 278 QDF_STATUS 279 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg) 280 { 281 struct peer_cfr *pe = NULL; 282 struct wlan_objmgr_vdev *vdev; 283 struct wlan_objmgr_pdev *pdev = NULL; 284 285 if (!peer) { 286 cfr_err("PEER is NULL\n"); 287 return QDF_STATUS_E_FAILURE; 288 } 289 290 vdev = wlan_peer_get_vdev(peer); 291 if (vdev) 292 pdev = wlan_vdev_get_pdev(vdev); 293 294 if (!pdev) { 295 cfr_err("PDEV is NULL\n"); 296 return QDF_STATUS_E_FAILURE; 297 } 298 299 if (wlan_cfr_is_feature_disabled(pdev)) { 300 cfr_debug("cfr is disabled"); 301 return QDF_STATUS_E_NOSUPPORT; 302 } 303 304 pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr)); 305 if (!pe) { 306 cfr_err("Failed to allocate peer_cfr object\n"); 307 return QDF_STATUS_E_FAILURE; 308 } 309 310 pe->peer_obj = peer; 311 312 /* Remaining will be populated when we give CFR capture command */ 313 wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR, 314 (void *)pe, QDF_STATUS_SUCCESS); 315 return QDF_STATUS_SUCCESS; 316 } 317 318 QDF_STATUS 319 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg) 320 { 321 struct peer_cfr *pe = NULL; 322 struct wlan_objmgr_vdev *vdev; 323 struct wlan_objmgr_pdev *pdev = NULL; 324 struct pdev_cfr *pa = NULL; 325 326 if (!peer) { 327 cfr_err("PEER is NULL\n"); 328 return QDF_STATUS_E_FAILURE; 329 } 330 331 vdev = wlan_peer_get_vdev(peer); 332 if (vdev) 333 pdev = wlan_vdev_get_pdev(vdev); 334 335 if (wlan_cfr_is_feature_disabled(pdev)) { 336 cfr_info("cfr is disabled"); 337 return QDF_STATUS_E_NOSUPPORT; 338 } 339 340 if (pdev) 341 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, 342 WLAN_UMAC_COMP_CFR); 343 344 pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); 345 346 if (pa && pe) { 347 if (pe->period && pe->request) 348 pa->cfr_current_sta_count--; 349 } 350 351 if (pe) { 352 wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR, 353 (void *)pe); 354 qdf_mem_free(pe); 355 } 356 357 return QDF_STATUS_SUCCESS; 358 } 359 360 #ifdef CFR_USE_FIXED_FOLDER 361 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev) 362 { 363 char *default_name = "wlan"; 364 365 return default_name; 366 } 367 #else 368 /** 369 * cfr_get_dev_name() - Get net device name from pdev 370 * @pdev: objmgr pdev 371 * 372 * Return: netdev name 373 */ 374 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev) 375 { 376 struct pdev_osif_priv *pdev_ospriv; 377 struct qdf_net_if *nif; 378 379 pdev_ospriv = wlan_pdev_get_ospriv(pdev); 380 if (!pdev_ospriv) { 381 cfr_err("pdev_ospriv is NULL\n"); 382 return NULL; 383 } 384 385 nif = pdev_ospriv->nif; 386 if (!nif) { 387 cfr_err("pdev nif is NULL\n"); 388 return NULL; 389 } 390 391 return qdf_net_if_get_devname(nif); 392 } 393 #endif 394 395 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev) 396 { 397 struct pdev_cfr *pa = NULL; 398 char *devname; 399 char folder[32]; 400 401 if (!pdev) { 402 cfr_err("PDEV is NULL\n"); 403 return QDF_STATUS_E_FAILURE; 404 } 405 406 if (wlan_cfr_is_feature_disabled(pdev)) { 407 cfr_info("cfr is disabled"); 408 return QDF_STATUS_COMP_DISABLED; 409 } 410 411 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 412 413 if (pa == NULL) { 414 cfr_err("pdev_cfr is NULL\n"); 415 return QDF_STATUS_E_FAILURE; 416 } 417 418 if (!pa->is_cfr_capable) { 419 cfr_err("CFR IS NOT SUPPORTED\n"); 420 return QDF_STATUS_E_FAILURE; 421 } 422 423 devname = cfr_get_dev_name(pdev); 424 if (!devname) { 425 cfr_err("devname is NULL\n"); 426 return QDF_STATUS_E_FAILURE; 427 } 428 429 snprintf(folder, sizeof(folder), "cfr%s", devname); 430 431 pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL); 432 433 if (!pa->dir_ptr) { 434 cfr_err("Directory create failed"); 435 return QDF_STATUS_E_FAILURE; 436 } 437 438 pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr, 439 pa->subbuf_size, 440 pa->num_subbufs, NULL); 441 442 if (!pa->chan_ptr) { 443 cfr_err("Chan create failed"); 444 qdf_streamfs_remove_dir_recursive(pa->dir_ptr); 445 pa->dir_ptr = NULL; 446 return QDF_STATUS_E_FAILURE; 447 } 448 449 return QDF_STATUS_SUCCESS; 450 } 451 452 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev) 453 { 454 struct pdev_cfr *pa = NULL; 455 456 if (wlan_cfr_is_feature_disabled(pdev)) { 457 cfr_info("cfr is disabled"); 458 return QDF_STATUS_COMP_DISABLED; 459 } 460 461 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 462 if (pa) { 463 if (pa->chan_ptr) { 464 qdf_streamfs_close(pa->chan_ptr); 465 pa->chan_ptr = NULL; 466 } 467 468 if (pa->dir_ptr) { 469 qdf_streamfs_remove_dir_recursive(pa->dir_ptr); 470 pa->dir_ptr = NULL; 471 } 472 473 } else 474 return QDF_STATUS_E_FAILURE; 475 476 return QDF_STATUS_SUCCESS; 477 } 478 479 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data, 480 size_t write_len) 481 { 482 if (pa->chan_ptr) { 483 /* write to channel buffer */ 484 qdf_streamfs_write(pa->chan_ptr, (const void *)write_data, 485 write_len); 486 } else 487 return QDF_STATUS_E_FAILURE; 488 489 return QDF_STATUS_SUCCESS; 490 } 491 492 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa) 493 { 494 if (pa->chan_ptr) { 495 496 /* Flush the data write to channel buffer */ 497 qdf_streamfs_flush(pa->chan_ptr); 498 } else 499 return QDF_STATUS_E_FAILURE; 500 501 return QDF_STATUS_SUCCESS; 502 } 503 504 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev) 505 { 506 struct pdev_cfr *pa; 507 uint32_t status; 508 struct wlan_objmgr_pdev *pdev; 509 510 pdev = wlan_vdev_get_pdev(vdev); 511 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 512 if (!pa) { 513 cfr_err("pdev_cfr is NULL\n"); 514 return QDF_STATUS_E_INVAL; 515 } 516 517 /* Don't write stop string if there is valid cfr_nl_cb. Since 518 * userspace needn't stop event string 519 */ 520 if (pa->nl_cb.cfr_nl_cb) 521 return QDF_STATUS_SUCCESS; 522 523 status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR, 524 sizeof(CFR_STOP_STR)); 525 526 status = cfr_streamfs_flush(pa); 527 cfr_debug("stop indication done"); 528 529 return status; 530 } 531 532 #ifdef WLAN_CFR_PM 533 QDF_STATUS cfr_prevent_suspend(struct pdev_cfr *pcfr) 534 { 535 if (!pcfr) { 536 cfr_debug("NULL pcfr"); 537 return QDF_STATUS_E_INVAL; 538 } 539 540 if (pcfr->is_prevent_suspend) { 541 cfr_debug("acquired wake lock"); 542 return QDF_STATUS_E_AGAIN; 543 } 544 qdf_wake_lock_acquire(&pcfr->wake_lock, 545 WIFI_POWER_EVENT_WAKELOCK_CFR); 546 qdf_runtime_pm_prevent_suspend(&pcfr->runtime_lock); 547 pcfr->is_prevent_suspend = true; 548 549 return QDF_STATUS_SUCCESS; 550 } 551 552 QDF_STATUS cfr_allow_suspend(struct pdev_cfr *pcfr) 553 { 554 if (!pcfr) { 555 cfr_debug("NULL pcfr"); 556 return QDF_STATUS_E_INVAL; 557 } 558 559 if (!pcfr->is_prevent_suspend) { 560 cfr_debug("wake lock not acquired"); 561 return QDF_STATUS_E_INVAL; 562 } 563 qdf_wake_lock_release(&pcfr->wake_lock, 564 WIFI_POWER_EVENT_WAKELOCK_CFR); 565 qdf_runtime_pm_allow_suspend(&pcfr->runtime_lock); 566 pcfr->is_prevent_suspend = false; 567 568 return QDF_STATUS_SUCCESS; 569 } 570 #endif 571