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