1 /* 2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <cfr_defs_i.h> 20 #include <qdf_types.h> 21 #include <wlan_objmgr_pdev_obj.h> 22 #include <wlan_objmgr_vdev_obj.h> 23 #include <wlan_objmgr_peer_obj.h> 24 #include <wlan_cfr_tgt_api.h> 25 #include <qdf_streamfs.h> 26 #include <target_if.h> 27 #include <target_if_direct_buf_rx_api.h> 28 #include <wlan_osif_priv.h> 29 #include <cfg_ucfg_api.h> 30 #include "cfr_cfg.h" 31 #ifdef WLAN_CFR_PM 32 #include "host_diag_core_event.h" 33 #endif 34 35 /** 36 * wlan_cfr_is_ini_disabled() - Check if cfr feature is disabled 37 * @pdev - the physical device object. 38 * 39 * Return : true if cfr is disabled, else false. 40 */ 41 static bool 42 wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev *pdev) 43 { 44 struct wlan_objmgr_psoc *psoc; 45 uint8_t cfr_disable_bitmap; 46 47 psoc = wlan_pdev_get_psoc(pdev); 48 if (!psoc) { 49 cfr_err("psoc is null"); 50 return true; 51 } 52 53 cfr_disable_bitmap = cfg_get(psoc, CFG_CFR_DISABLE); 54 55 if (cfr_disable_bitmap & (1 << wlan_objmgr_pdev_get_pdev_id(pdev))) { 56 cfr_info("cfr is disabled for pdev[%d]", 57 wlan_objmgr_pdev_get_pdev_id(pdev)); 58 return true; 59 } 60 61 return false; 62 } 63 64 /** 65 * wlan_cfr_get_dbr_num_entries() - Get entry number of DBR ring 66 * @pdev - the physical device object. 67 * 68 * Return : Entry number of DBR ring. 69 */ 70 static uint32_t 71 wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev *pdev) 72 { 73 struct wlan_objmgr_psoc *psoc; 74 struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap; 75 uint8_t num_dbr_ring_caps, cap_idx, pdev_id; 76 struct target_psoc_info *tgt_psoc_info; 77 uint32_t num_entries = MAX_LUT_ENTRIES; 78 79 if (!pdev) { 80 cfr_err("Invalid pdev"); 81 return num_entries; 82 } 83 84 psoc = wlan_pdev_get_psoc(pdev); 85 if (!psoc) { 86 cfr_err("psoc is null"); 87 return num_entries; 88 } 89 90 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 91 if (!tgt_psoc_info) { 92 cfr_err("target_psoc_info is null"); 93 return num_entries; 94 } 95 96 num_dbr_ring_caps = target_psoc_get_num_dbr_ring_caps(tgt_psoc_info); 97 dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info); 98 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 99 100 for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) { 101 if (dbr_ring_cap[cap_idx].pdev_id == pdev_id && 102 dbr_ring_cap[cap_idx].mod_id == DBR_MODULE_CFR) 103 num_entries = dbr_ring_cap[cap_idx].ring_elems_min; 104 } 105 106 num_entries = QDF_MIN(num_entries, MAX_LUT_ENTRIES); 107 cfr_debug("pdev id %d, num_entries %d", pdev_id, num_entries); 108 109 return num_entries; 110 } 111 112 #ifdef WLAN_CFR_PM 113 /** 114 * cfr_wakelock_init(): Create/init wake lock for CFR 115 * 116 * Create/init wake lock for CFR 117 * 118 * Return None 119 */ 120 static void cfr_wakelock_init(struct pdev_cfr *pcfr) 121 { 122 if (!pcfr) { 123 cfr_debug("NULL pa"); 124 return; 125 } 126 127 pcfr->is_prevent_suspend = false; 128 qdf_wake_lock_create(&pcfr->wake_lock, "wlan_cfr"); 129 qdf_runtime_lock_init(&pcfr->runtime_lock); 130 } 131 132 /** 133 * cfr_wakelock_deinit(): Destroy/deinit wake lock for CFR 134 * 135 * Destroy/deinit wake lock for CFR 136 * 137 * Return None 138 */ 139 static void cfr_wakelock_deinit(struct pdev_cfr *pcfr) 140 { 141 if (!pcfr) { 142 cfr_debug("NULL pa"); 143 return; 144 } 145 146 qdf_runtime_lock_deinit(&pcfr->runtime_lock); 147 qdf_wake_lock_destroy(&pcfr->wake_lock); 148 } 149 #else 150 static inline void cfr_wakelock_init(struct pdev_cfr *pcfr) 151 { 152 } 153 154 static inline void cfr_wakelock_deinit(struct pdev_cfr *pcfr) 155 { 156 } 157 #endif 158 159 QDF_STATUS 160 wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg) 161 { 162 struct psoc_cfr *cfr_sc = NULL; 163 164 cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr)); 165 if (!cfr_sc) { 166 cfr_err("Failed to allocate cfr_ctx object\n"); 167 return QDF_STATUS_E_NOMEM; 168 } 169 170 cfr_sc->psoc_obj = psoc; 171 172 wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR, 173 (void *)cfr_sc, 174 QDF_STATUS_SUCCESS); 175 176 return QDF_STATUS_SUCCESS; 177 } 178 179 QDF_STATUS 180 wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg) 181 { 182 struct psoc_cfr *cfr_sc = NULL; 183 184 cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc, 185 WLAN_UMAC_COMP_CFR); 186 if (cfr_sc) { 187 wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR, 188 (void *)cfr_sc); 189 qdf_mem_free(cfr_sc); 190 } 191 192 return QDF_STATUS_SUCCESS; 193 } 194 195 QDF_STATUS 196 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg) 197 { 198 struct pdev_cfr *pa = NULL; 199 uint32_t idx; 200 201 if (!pdev) { 202 cfr_err("PDEV is NULL\n"); 203 return QDF_STATUS_E_FAILURE; 204 } 205 206 if (wlan_cfr_is_ini_disabled(pdev)) { 207 wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN); 208 return QDF_STATUS_E_NOSUPPORT; 209 } 210 211 wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN); 212 213 pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr)); 214 if (!pa) { 215 cfr_err("Failed to allocate pdev_cfr object\n"); 216 return QDF_STATUS_E_NOMEM; 217 } 218 pa->pdev_obj = pdev; 219 pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev); 220 if (!pa->lut_num) { 221 cfr_err("lut num is 0"); 222 qdf_mem_free(pa); 223 return QDF_STATUS_E_INVAL; 224 } 225 pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num * 226 sizeof(struct look_up_table *)); 227 if (!pa->lut) { 228 cfr_err("Failed to allocate lut, lut num %d", pa->lut_num); 229 qdf_mem_free(pa); 230 return QDF_STATUS_E_NOMEM; 231 } 232 for (idx = 0; idx < pa->lut_num; idx++) 233 pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc( 234 sizeof(struct look_up_table)); 235 236 cfr_wakelock_init(pa); 237 wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR, 238 (void *)pa, QDF_STATUS_SUCCESS); 239 240 return QDF_STATUS_SUCCESS; 241 } 242 243 QDF_STATUS 244 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg) 245 { 246 struct pdev_cfr *pa = NULL; 247 uint32_t idx; 248 249 if (!pdev) { 250 cfr_err("PDEV is NULL\n"); 251 return QDF_STATUS_E_FAILURE; 252 } 253 254 if (wlan_cfr_is_feature_disabled(pdev)) { 255 cfr_info("cfr is disabled"); 256 return QDF_STATUS_E_NOSUPPORT; 257 } 258 259 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 260 if (pa) { 261 cfr_wakelock_deinit(pa); 262 wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR, 263 (void *)pa); 264 if (pa->lut) { 265 for (idx = 0; idx < pa->lut_num; idx++) 266 qdf_mem_free(pa->lut[idx]); 267 qdf_mem_free(pa->lut); 268 } 269 qdf_mem_free(pa); 270 } 271 272 return QDF_STATUS_SUCCESS; 273 } 274 275 QDF_STATUS 276 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg) 277 { 278 struct peer_cfr *pe = NULL; 279 struct wlan_objmgr_vdev *vdev; 280 struct wlan_objmgr_pdev *pdev = NULL; 281 282 if (!peer) { 283 cfr_err("PEER is NULL\n"); 284 return QDF_STATUS_E_FAILURE; 285 } 286 287 vdev = wlan_peer_get_vdev(peer); 288 if (vdev) 289 pdev = wlan_vdev_get_pdev(vdev); 290 291 if (!pdev) { 292 cfr_err("PDEV is NULL\n"); 293 return QDF_STATUS_E_FAILURE; 294 } 295 296 if (wlan_cfr_is_feature_disabled(pdev)) { 297 cfr_info("cfr is disabled"); 298 return QDF_STATUS_E_NOSUPPORT; 299 } 300 301 pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr)); 302 if (!pe) { 303 cfr_err("Failed to allocate peer_cfr object\n"); 304 return QDF_STATUS_E_FAILURE; 305 } 306 307 pe->peer_obj = peer; 308 309 /* Remaining will be populated when we give CFR capture command */ 310 wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR, 311 (void *)pe, QDF_STATUS_SUCCESS); 312 return QDF_STATUS_SUCCESS; 313 } 314 315 QDF_STATUS 316 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg) 317 { 318 struct peer_cfr *pe = NULL; 319 struct wlan_objmgr_vdev *vdev; 320 struct wlan_objmgr_pdev *pdev = NULL; 321 struct pdev_cfr *pa = NULL; 322 323 if (!peer) { 324 cfr_err("PEER is NULL\n"); 325 return QDF_STATUS_E_FAILURE; 326 } 327 328 vdev = wlan_peer_get_vdev(peer); 329 if (vdev) 330 pdev = wlan_vdev_get_pdev(vdev); 331 332 if (wlan_cfr_is_feature_disabled(pdev)) { 333 cfr_info("cfr is disabled"); 334 return QDF_STATUS_E_NOSUPPORT; 335 } 336 337 if (pdev) 338 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, 339 WLAN_UMAC_COMP_CFR); 340 341 pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); 342 343 if (pa && pe) { 344 if (pe->period && pe->request) 345 pa->cfr_current_sta_count--; 346 } 347 348 if (pe) { 349 wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR, 350 (void *)pe); 351 qdf_mem_free(pe); 352 } 353 354 return QDF_STATUS_SUCCESS; 355 } 356 357 #ifdef CFR_USE_FIXED_FOLDER 358 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev) 359 { 360 char *default_name = "wlan"; 361 362 return default_name; 363 } 364 #else 365 /** 366 * cfr_get_dev_name() - Get net device name from pdev 367 * @pdev: objmgr pdev 368 * 369 * Return: netdev name 370 */ 371 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev) 372 { 373 struct pdev_osif_priv *pdev_ospriv; 374 struct qdf_net_if *nif; 375 376 pdev_ospriv = wlan_pdev_get_ospriv(pdev); 377 if (!pdev_ospriv) { 378 cfr_err("pdev_ospriv is NULL\n"); 379 return NULL; 380 } 381 382 nif = pdev_ospriv->nif; 383 if (!nif) { 384 cfr_err("pdev nif is NULL\n"); 385 return NULL; 386 } 387 388 return qdf_net_if_get_devname(nif); 389 } 390 #endif 391 392 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev) 393 { 394 struct pdev_cfr *pa = NULL; 395 char *devname; 396 char folder[32]; 397 398 if (!pdev) { 399 cfr_err("PDEV is NULL\n"); 400 return QDF_STATUS_E_FAILURE; 401 } 402 403 if (wlan_cfr_is_feature_disabled(pdev)) { 404 cfr_info("cfr is disabled"); 405 return QDF_STATUS_COMP_DISABLED; 406 } 407 408 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 409 410 if (pa == NULL) { 411 cfr_err("pdev_cfr is NULL\n"); 412 return QDF_STATUS_E_FAILURE; 413 } 414 415 if (!pa->is_cfr_capable) { 416 cfr_err("CFR IS NOT SUPPORTED\n"); 417 return QDF_STATUS_E_FAILURE; 418 } 419 420 devname = cfr_get_dev_name(pdev); 421 if (!devname) { 422 cfr_err("devname is NULL\n"); 423 return QDF_STATUS_E_FAILURE; 424 } 425 426 snprintf(folder, sizeof(folder), "cfr%s", devname); 427 428 pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL); 429 430 if (!pa->dir_ptr) { 431 cfr_err("Directory create failed"); 432 return QDF_STATUS_E_FAILURE; 433 } 434 435 pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr, 436 pa->subbuf_size, 437 pa->num_subbufs, NULL); 438 439 if (!pa->chan_ptr) { 440 cfr_err("Chan create failed"); 441 qdf_streamfs_remove_dir_recursive(pa->dir_ptr); 442 pa->dir_ptr = NULL; 443 return QDF_STATUS_E_FAILURE; 444 } 445 446 return QDF_STATUS_SUCCESS; 447 } 448 449 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev) 450 { 451 struct pdev_cfr *pa = NULL; 452 453 if (wlan_cfr_is_feature_disabled(pdev)) { 454 cfr_info("cfr is disabled"); 455 return QDF_STATUS_COMP_DISABLED; 456 } 457 458 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 459 if (pa) { 460 if (pa->chan_ptr) { 461 qdf_streamfs_close(pa->chan_ptr); 462 pa->chan_ptr = NULL; 463 } 464 465 if (pa->dir_ptr) { 466 qdf_streamfs_remove_dir_recursive(pa->dir_ptr); 467 pa->dir_ptr = NULL; 468 } 469 470 } else 471 return QDF_STATUS_E_FAILURE; 472 473 return QDF_STATUS_SUCCESS; 474 } 475 476 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data, 477 size_t write_len) 478 { 479 if (pa->chan_ptr) { 480 /* write to channel buffer */ 481 qdf_streamfs_write(pa->chan_ptr, (const void *)write_data, 482 write_len); 483 } else 484 return QDF_STATUS_E_FAILURE; 485 486 return QDF_STATUS_SUCCESS; 487 } 488 489 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa) 490 { 491 if (pa->chan_ptr) { 492 493 /* Flush the data write to channel buffer */ 494 qdf_streamfs_flush(pa->chan_ptr); 495 } else 496 return QDF_STATUS_E_FAILURE; 497 498 return QDF_STATUS_SUCCESS; 499 } 500 501 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev) 502 { 503 struct pdev_cfr *pa; 504 uint32_t status; 505 struct wlan_objmgr_pdev *pdev; 506 507 pdev = wlan_vdev_get_pdev(vdev); 508 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 509 if (!pa) { 510 cfr_err("pdev_cfr is NULL\n"); 511 return QDF_STATUS_E_INVAL; 512 } 513 514 if (pa->nl_cb.cfr_nl_cb) { 515 pa->nl_cb.cfr_nl_cb(pa->nl_cb.vdev_id, pa->nl_cb.pid, 516 (const void *)CFR_STOP_STR, 517 sizeof(CFR_STOP_STR)); 518 519 return QDF_STATUS_SUCCESS; 520 } 521 522 status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR, 523 sizeof(CFR_STOP_STR)); 524 525 status = cfr_streamfs_flush(pa); 526 cfr_debug("stop indication done"); 527 528 return status; 529 } 530 531 #ifdef WLAN_CFR_PM 532 QDF_STATUS cfr_prevent_suspend(struct pdev_cfr *pcfr) 533 { 534 if (!pcfr) { 535 cfr_debug("NULL pcfr"); 536 return QDF_STATUS_E_INVAL; 537 } 538 539 if (pcfr->is_prevent_suspend) { 540 cfr_debug("acquired wake lock"); 541 return QDF_STATUS_E_AGAIN; 542 } 543 qdf_wake_lock_acquire(&pcfr->wake_lock, 544 WIFI_POWER_EVENT_WAKELOCK_CFR); 545 qdf_runtime_pm_prevent_suspend(&pcfr->runtime_lock); 546 pcfr->is_prevent_suspend = true; 547 548 return QDF_STATUS_SUCCESS; 549 } 550 551 QDF_STATUS cfr_allow_suspend(struct pdev_cfr *pcfr) 552 { 553 if (!pcfr) { 554 cfr_debug("NULL pcfr"); 555 return QDF_STATUS_E_INVAL; 556 } 557 558 if (!pcfr->is_prevent_suspend) { 559 cfr_debug("wake lock not acquired"); 560 return QDF_STATUS_E_INVAL; 561 } 562 qdf_wake_lock_release(&pcfr->wake_lock, 563 WIFI_POWER_EVENT_WAKELOCK_CFR); 564 qdf_runtime_pm_allow_suspend(&pcfr->runtime_lock); 565 pcfr->is_prevent_suspend = false; 566 567 return QDF_STATUS_SUCCESS; 568 } 569 #endif 570