1 /* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 */ 15 16 /* 17 * DOC: contains MLO manager ap related functionality 18 */ 19 #include "wlan_mlo_mgr_cmn.h" 20 #include "wlan_mlo_mgr_main.h" 21 #ifdef WLAN_MLO_MULTI_CHIP 22 #include "wlan_lmac_if_def.h" 23 #include <cdp_txrx_mlo.h> 24 #endif 25 #include <wlan_mgmt_txrx_rx_reo_utils_api.h> 26 27 #ifdef WLAN_MLO_MULTI_CHIP 28 static inline 29 bool mlo_psoc_get_index_id(struct wlan_objmgr_psoc *psoc, 30 uint8_t grp_id, 31 uint8_t *index, 32 bool teardown) 33 { 34 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 35 uint8_t id; 36 37 if (!mlo_ctx) 38 return false; 39 40 if (!psoc) 41 return false; 42 43 if (!index) 44 return false; 45 46 if (grp_id >= mlo_ctx->total_grp) { 47 mlo_err("Invalid grp id %d, total no of groups %d", 48 grp_id, mlo_ctx->total_grp); 49 return false; 50 } 51 52 for (id = 0; id < mlo_ctx->setup_info[grp_id].tot_socs; id++) 53 if (mlo_ctx->setup_info[grp_id].curr_soc_list[id] == psoc) { 54 *index = id; 55 return true; 56 } 57 58 if (teardown) 59 return false; 60 61 for (id = 0; id < mlo_ctx->setup_info[grp_id].tot_socs; id++) 62 if (!mlo_ctx->setup_info[grp_id].curr_soc_list[id]) { 63 *index = id; 64 return true; 65 } 66 67 return false; 68 } 69 70 bool mlo_psoc_get_grp_id(struct wlan_objmgr_psoc *psoc, uint8_t *ret_id) 71 { 72 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 73 uint8_t grp_id; 74 uint8_t tot_socs; 75 uint8_t id; 76 77 if (!mlo_ctx) 78 return false; 79 80 if (!psoc) 81 return false; 82 83 if (!ret_id) 84 return false; 85 86 for (grp_id = 0; grp_id < mlo_ctx->total_grp; grp_id++) { 87 tot_socs = mlo_ctx->setup_info[grp_id].tot_socs; 88 for (id = 0; id < tot_socs; id++) 89 if (mlo_ctx->setup_info[grp_id].soc_list[id] == psoc) { 90 *ret_id = grp_id; 91 return true; 92 } 93 } 94 95 return false; 96 } 97 98 qdf_export_symbol(mlo_psoc_get_grp_id); 99 100 bool mlo_is_ml_soc(struct wlan_objmgr_psoc *psoc, uint8_t grp_id) 101 { 102 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 103 uint8_t id; 104 105 if (!mlo_ctx) 106 return false; 107 108 if (!psoc) 109 return false; 110 111 if (grp_id >= mlo_ctx->total_grp) { 112 mlo_err("Invalid grp id %d, total no of groups %d", 113 grp_id, mlo_ctx->total_grp); 114 return false; 115 } 116 117 for (id = 0; id < mlo_ctx->setup_info[grp_id].tot_socs; id++) 118 if (mlo_ctx->setup_info[grp_id].curr_soc_list[id] == psoc) 119 return true; 120 121 return false; 122 } 123 124 qdf_export_symbol(mlo_is_ml_soc); 125 126 static void mlo_set_soc_list(uint8_t grp_id, struct wlan_objmgr_psoc *psoc) 127 { 128 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 129 uint8_t idx; 130 131 if (!mlo_ctx) 132 return; 133 134 if (!psoc) 135 return; 136 137 if (grp_id >= mlo_ctx->total_grp) { 138 mlo_err("Invalid grp id %d, total no of groups %d", 139 grp_id, mlo_ctx->total_grp); 140 return; 141 } 142 143 for (idx = 0; idx < mlo_ctx->setup_info[grp_id].tot_socs; idx++) { 144 if (mlo_ctx->setup_info[grp_id].soc_id_list[idx] == 145 psoc->soc_objmgr.psoc_id) { 146 mlo_ctx->setup_info[grp_id].soc_list[idx] = psoc; 147 } 148 } 149 } 150 151 void mlo_get_soc_list(struct wlan_objmgr_psoc **soc_list, 152 uint8_t grp_id, 153 uint8_t total_socs, 154 enum MLO_SOC_LIST curr) 155 { 156 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 157 uint8_t chip_idx; 158 159 if (!mlo_ctx) 160 goto err_case; 161 162 if (grp_id >= mlo_ctx->total_grp) { 163 mlo_err("Invalid grp id %d, total no of groups %d", 164 grp_id, mlo_ctx->total_grp); 165 goto err_case; 166 } 167 168 if (total_socs != mlo_ctx->setup_info[grp_id].tot_socs) { 169 mlo_err("Mismatch in number of socs in the grp id %d, expected %d observed %d", 170 grp_id, total_socs, 171 mlo_ctx->setup_info[grp_id].tot_socs); 172 goto err_case; 173 } 174 175 if (curr == WLAN_MLO_GROUP_CURRENT_SOC_LIST) { 176 for (chip_idx = 0; chip_idx < total_socs; chip_idx++) 177 soc_list[chip_idx] = 178 mlo_ctx->setup_info[grp_id].curr_soc_list[chip_idx]; 179 } else { 180 for (chip_idx = 0; chip_idx < total_socs; chip_idx++) 181 soc_list[chip_idx] = 182 mlo_ctx->setup_info[grp_id].soc_list[chip_idx]; 183 } 184 185 return; 186 187 err_case: 188 for (chip_idx = 0; chip_idx < total_socs; chip_idx++) 189 soc_list[chip_idx] = NULL; 190 191 return; 192 } 193 194 qdf_export_symbol(mlo_get_soc_list); 195 196 void mlo_cleanup_asserted_soc_setup_info(struct wlan_objmgr_psoc *psoc, 197 uint8_t grp_id) 198 { 199 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 200 uint8_t link_idx; 201 struct wlan_objmgr_pdev *pdev; 202 struct mlo_setup_info *setup_info; 203 204 if (!mlo_ctx) 205 return; 206 207 if (!psoc) 208 return; 209 210 if (grp_id >= mlo_ctx->total_grp) { 211 mlo_err("Invalid grp id %d, total no of groups %d", 212 grp_id, mlo_ctx->total_grp); 213 return; 214 } 215 216 setup_info = &mlo_ctx->setup_info[grp_id]; 217 218 if (!setup_info->num_links) 219 return; 220 221 if (!psoc) { 222 mlo_info("NULL psoc"); 223 return; 224 } 225 226 for (link_idx = 0; link_idx < MAX_MLO_LINKS; link_idx++) { 227 pdev = setup_info->pdev_list[link_idx]; 228 if (pdev) { 229 if (wlan_pdev_get_psoc(pdev) == psoc) { 230 setup_info->pdev_list[link_idx] = NULL; 231 setup_info->state[link_idx] = MLO_LINK_TEARDOWN; 232 setup_info->num_links--; 233 } 234 } 235 } 236 } 237 238 qdf_export_symbol(mlo_cleanup_asserted_soc_setup_info); 239 240 void mlo_setup_update_soc_id_list(uint8_t grp_id, uint8_t *soc_id_list) 241 { 242 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 243 uint32_t tot_socs; 244 uint32_t num_soc; 245 uint8_t *soc_list; 246 247 if (!mlo_ctx) 248 return; 249 250 if (grp_id >= mlo_ctx->total_grp) { 251 mlo_err("Invalid grp id %d, total no of groups %d", 252 grp_id, mlo_ctx->total_grp); 253 return; 254 } 255 256 tot_socs = mlo_ctx->setup_info[grp_id].tot_socs; 257 soc_list = mlo_ctx->setup_info[grp_id].soc_id_list; 258 259 for (num_soc = 0; num_soc < tot_socs; num_soc++) 260 soc_list[num_soc] = soc_id_list[num_soc]; 261 } 262 263 qdf_export_symbol(mlo_setup_update_soc_id_list); 264 265 uint8_t mlo_setup_get_total_socs(uint8_t grp_id) 266 { 267 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 268 269 if (!mlo_ctx) 270 return 0; 271 272 if (grp_id >= mlo_ctx->total_grp) { 273 mlo_err("Invalid grp id %d, total no of groups %d", 274 grp_id, mlo_ctx->total_grp); 275 return 0; 276 } 277 278 return mlo_ctx->setup_info[grp_id].tot_socs; 279 } 280 281 qdf_export_symbol(mlo_setup_get_total_socs); 282 283 void mlo_setup_update_total_socs(uint8_t grp_id, uint8_t tot_socs) 284 { 285 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 286 287 if (!mlo_ctx) 288 return; 289 290 if (grp_id >= mlo_ctx->total_grp) { 291 mlo_err("Invalid grp id %d, total no of groups %d", 292 grp_id, mlo_ctx->total_grp); 293 return; 294 } 295 296 mlo_ctx->setup_info[grp_id].tot_socs = tot_socs; 297 mlo_ctx->setup_info[grp_id].ml_grp_id = grp_id; 298 } 299 300 qdf_export_symbol(mlo_setup_update_total_socs); 301 302 static QDF_STATUS mlo_find_pdev_idx(struct wlan_objmgr_pdev *pdev, 303 uint8_t *link_idx, uint8_t grp_id) 304 { 305 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 306 uint8_t idx; 307 308 if (!mlo_ctx) 309 return QDF_STATUS_E_FAILURE; 310 311 if (!pdev) 312 return QDF_STATUS_E_FAILURE; 313 314 if (!link_idx) 315 return QDF_STATUS_E_FAILURE; 316 317 if (grp_id >= mlo_ctx->total_grp) { 318 mlo_err("Invalid grp id %d, total no of groups %d", 319 grp_id, mlo_ctx->total_grp); 320 return QDF_STATUS_E_FAILURE; 321 } 322 323 for (idx = 0; idx < mlo_ctx->setup_info[grp_id].tot_links; idx++) { 324 if (mlo_ctx->setup_info[grp_id].pdev_list[idx] == pdev) { 325 *link_idx = idx; 326 return QDF_STATUS_SUCCESS; 327 } 328 } 329 330 return QDF_STATUS_E_FAILURE; 331 } 332 333 #define WLAN_SOC_ID_NOT_INITIALIZED -1 334 bool mlo_vdevs_check_single_soc(struct wlan_objmgr_vdev **wlan_vdev_list, 335 uint8_t vdev_count) 336 { 337 int i; 338 uint8_t soc_id = WLAN_SOC_ID_NOT_INITIALIZED; 339 340 for (i = 0; i < vdev_count; i++) { 341 uint8_t vdev_soc_id = wlan_vdev_get_psoc_id(wlan_vdev_list[i]); 342 343 if (i == 0) 344 soc_id = vdev_soc_id; 345 else if (soc_id != vdev_soc_id) 346 return false; 347 } 348 349 return true; 350 } 351 352 qdf_export_symbol(mlo_vdevs_check_single_soc); 353 354 static void mlo_check_state(struct wlan_objmgr_psoc *psoc, 355 void *obj, void *args) 356 { 357 struct wlan_objmgr_pdev *pdev; 358 uint8_t link_idx; 359 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 360 struct mlo_state_params *params = (struct mlo_state_params *)args; 361 362 uint8_t grp_id = params->grp_id; 363 pdev = (struct wlan_objmgr_pdev *)obj; 364 365 if (!mlo_ctx) 366 return; 367 368 if (!psoc) 369 return; 370 371 if (grp_id >= mlo_ctx->total_grp) { 372 mlo_err("Invalid grp id %d, total no of groups %d", 373 grp_id, mlo_ctx->total_grp); 374 return; 375 } 376 377 if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) { 378 mlo_info("Failed to find pdev"); 379 return; 380 } 381 382 if (mlo_ctx->setup_info[grp_id].state[link_idx] != params->check_state) 383 params->link_state_fail = 1; 384 } 385 386 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc, 387 uint8_t grp_id, 388 enum MLO_LINK_STATE state) 389 { 390 QDF_STATUS status = QDF_STATUS_E_INVAL; 391 struct mlo_state_params params = {0}; 392 393 params.check_state = state; 394 params.grp_id = grp_id; 395 396 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 397 mlo_check_state, ¶ms, 398 0, WLAN_MLME_NB_ID); 399 400 if (params.link_state_fail) 401 status = QDF_STATUS_E_INVAL; 402 else 403 status = QDF_STATUS_SUCCESS; 404 405 return status; 406 } 407 408 void mlo_setup_init(uint8_t total_grp) 409 { 410 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 411 struct mlo_setup_info *setup_info; 412 uint8_t id; 413 414 if (!mlo_ctx) 415 return; 416 417 if (!total_grp && total_grp > WLAN_MAX_MLO_GROUPS) { 418 mlo_err("Total number of groups (%d) is greater than MAX (%d), MLD Setup failed!!", 419 total_grp, WLAN_MAX_MLO_GROUPS); 420 return; 421 } 422 423 mlo_ctx->total_grp = total_grp; 424 setup_info = qdf_mem_malloc(sizeof(struct mlo_setup_info) * 425 total_grp); 426 427 if (!setup_info) 428 return; 429 430 mlo_ctx->setup_info = setup_info; 431 mlo_ctx->setup_info[0].ml_grp_id = 0; 432 for (id = 0; id < total_grp; id++) { 433 if (qdf_event_create(&mlo_ctx->setup_info[id].event) != 434 QDF_STATUS_SUCCESS) 435 mlo_err("Unable to create teardown event"); 436 } 437 } 438 439 qdf_export_symbol(mlo_setup_init); 440 441 void mlo_setup_deinit(void) 442 { 443 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 444 uint8_t id; 445 446 if (!mlo_ctx) 447 return; 448 449 if (!mlo_ctx->setup_info) 450 return; 451 452 for (id = 0; id < mlo_ctx->total_grp; id++) 453 qdf_event_destroy(&mlo_ctx->setup_info[id].event); 454 455 qdf_mem_free(mlo_ctx->setup_info); 456 mlo_ctx->setup_info = NULL; 457 } 458 459 qdf_export_symbol(mlo_setup_deinit); 460 461 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc, 462 uint8_t grp_id, uint8_t num_links) 463 { 464 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 465 466 if (!mlo_ctx) 467 return; 468 469 if (!psoc) 470 return; 471 472 if (grp_id >= mlo_ctx->total_grp) { 473 mlo_err("Invalid grp id %d, total no of groups %d", 474 grp_id, mlo_ctx->total_grp); 475 return; 476 } 477 478 mlo_ctx->setup_info[grp_id].tot_links += num_links; 479 } 480 481 qdf_export_symbol(mlo_setup_update_num_links); 482 483 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc, uint8_t grp_id) 484 { 485 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 486 struct mlo_setup_info *setup_info; 487 uint8_t chip_idx, tot_socs; 488 struct cdp_mlo_ctxt *dp_mlo_ctxt; 489 490 if (!mlo_ctx) 491 return; 492 493 if (!psoc) 494 return; 495 496 if (grp_id >= mlo_ctx->total_grp) { 497 mlo_err("Invalid grp id %d, total no of groups %d", 498 grp_id, mlo_ctx->total_grp); 499 return; 500 } 501 502 setup_info = &mlo_ctx->setup_info[grp_id]; 503 504 if (!setup_info->tot_socs) 505 return; 506 507 tot_socs = setup_info->tot_socs; 508 if (!mlo_psoc_get_index_id(psoc, grp_id, &chip_idx, 0)) { 509 mlo_err("Unable to fetch chip idx for psoc id %d grp id %d", 510 psoc->soc_objmgr.psoc_id, 511 grp_id); 512 return; 513 } 514 515 if (!(chip_idx < tot_socs)) { 516 mlo_err("Invalid chip index, SoC setup failed"); 517 return; 518 } 519 520 setup_info->curr_soc_list[chip_idx] = psoc; 521 mlo_set_soc_list(grp_id, psoc); 522 setup_info->num_soc++; 523 524 mlo_debug("SoC updated to mld grp %d , chip idx %d num soc %d", 525 grp_id, chip_idx, setup_info->num_soc); 526 527 if (setup_info->num_soc != tot_socs) 528 return; 529 530 dp_mlo_ctxt = cdp_mlo_ctxt_attach(wlan_psoc_get_dp_handle(psoc), 531 (struct cdp_ctrl_mlo_mgr *)mlo_ctx); 532 wlan_objmgr_set_dp_mlo_ctx(dp_mlo_ctxt, grp_id); 533 534 for (chip_idx = 0; chip_idx < tot_socs; chip_idx++) { 535 struct wlan_objmgr_psoc *tmp_soc = 536 setup_info->curr_soc_list[chip_idx]; 537 if (tmp_soc) 538 cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc), 539 setup_info->dp_handle); 540 } 541 542 cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc), 543 setup_info->dp_handle); 544 } 545 546 qdf_export_symbol(mlo_setup_update_soc_ready); 547 548 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev, uint8_t grp_id) 549 { 550 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 551 struct mlo_setup_info *setup_info; 552 uint8_t link_idx; 553 uint16_t link_id; 554 555 if (!mlo_ctx) 556 return; 557 558 if (!pdev) 559 return; 560 561 if (grp_id >= mlo_ctx->total_grp) { 562 mlo_err("Invalid grp id %d, total no of groups %d", 563 grp_id, mlo_ctx->total_grp); 564 return; 565 } 566 567 setup_info = &mlo_ctx->setup_info[grp_id]; 568 569 if (!setup_info->tot_links) { 570 mlo_err("Setup info total links %d for grp id %d", 571 setup_info->tot_links, grp_id); 572 return; 573 } 574 575 if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) == QDF_STATUS_SUCCESS) { 576 mlo_debug("Pdev already part of list link idx %d", link_idx); 577 return; 578 } 579 580 for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++) 581 if (!setup_info->pdev_list[link_idx]) 582 break; 583 584 if (link_idx >= setup_info->tot_links) { 585 mlo_err("Exceeding max total mld links"); 586 return; 587 } 588 589 setup_info->pdev_list[link_idx] = pdev; 590 setup_info->state[link_idx] = MLO_LINK_SETUP_INIT; 591 setup_info->num_links++; 592 593 link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 594 if (link_id == INVALID_HW_LINK_ID) { 595 mlo_err("Invalid HW link id for the pdev"); 596 return; 597 } 598 setup_info->valid_link_bitmap |= (1 << link_id); 599 600 mlo_debug("Pdev updated to Grp id %d mld link %d num_links %d hw link id %d Valid link bitmap %d", 601 grp_id, link_idx, setup_info->num_links, 602 link_id, setup_info->valid_link_bitmap); 603 604 qdf_assert_always(link_idx < MAX_MLO_LINKS); 605 606 if (setup_info->num_links == setup_info->tot_links && 607 setup_info->num_soc == setup_info->tot_socs) { 608 struct wlan_objmgr_psoc *psoc; 609 struct wlan_lmac_if_tx_ops *tx_ops; 610 QDF_STATUS status; 611 612 psoc = wlan_pdev_get_psoc(pdev); 613 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 614 615 status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc); 616 if (QDF_IS_STATUS_ERROR(status)) { 617 mlo_err("Failed to validate MLO HW link info"); 618 qdf_assert_always(0); 619 } 620 621 mlo_debug("Trigger MLO Setup request"); 622 if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) { 623 tx_ops->mops.target_if_mlo_setup_req( 624 setup_info->pdev_list, 625 setup_info->num_links, 626 grp_id); 627 } 628 } 629 } 630 631 qdf_export_symbol(mlo_setup_link_ready); 632 633 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev, uint8_t grp_id) 634 { 635 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 636 struct mlo_setup_info *setup_info; 637 uint8_t link_idx; 638 639 if (!mlo_ctx) 640 return; 641 642 if (!pdev) 643 return; 644 645 if (grp_id >= mlo_ctx->total_grp) { 646 mlo_err("Invalid grp id %d, total no of groups %d", 647 grp_id, mlo_ctx->total_grp); 648 return; 649 } 650 651 setup_info = &mlo_ctx->setup_info[grp_id]; 652 653 for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++) 654 if (setup_info->pdev_list[link_idx] == pdev) { 655 setup_info->state[link_idx] = 656 MLO_LINK_SETUP_DONE; 657 break; 658 } 659 660 mlo_debug("Setup complete for pdev id %d mlo group %d", 661 pdev->pdev_objmgr.wlan_pdev_id, grp_id); 662 663 for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++) 664 if (setup_info->state[link_idx] == MLO_LINK_SETUP_DONE) 665 continue; 666 else 667 break; 668 669 if (link_idx == setup_info->tot_links) { 670 struct wlan_objmgr_psoc *psoc; 671 struct wlan_lmac_if_tx_ops *tx_ops; 672 673 psoc = wlan_pdev_get_psoc(pdev); 674 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 675 mlo_debug("Trigger MLO ready"); 676 if (tx_ops && tx_ops->mops.target_if_mlo_ready) { 677 tx_ops->mops.target_if_mlo_ready( 678 setup_info->pdev_list, 679 setup_info->num_links); 680 } 681 } 682 } 683 684 qdf_export_symbol(mlo_link_setup_complete); 685 686 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc, 687 void *obj, void *args) 688 { 689 struct wlan_objmgr_pdev *pdev; 690 uint8_t link_idx; 691 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 692 struct mlo_setup_info *setup_info; 693 uint16_t link_id; 694 uint8_t grp_id = *(uint8_t *)args; 695 696 if (!mlo_ctx) 697 return; 698 699 if (!psoc) 700 return; 701 702 if (grp_id >= mlo_ctx->total_grp) { 703 mlo_err("Invalid grp id %d, total no of groups %d", 704 grp_id, mlo_ctx->total_grp); 705 return; 706 } 707 708 setup_info = &mlo_ctx->setup_info[grp_id]; 709 710 pdev = (struct wlan_objmgr_pdev *)obj; 711 712 if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) { 713 mlo_info("Failed to find pdev"); 714 return; 715 } 716 717 setup_info->pdev_list[link_idx] = NULL; 718 setup_info->state[link_idx] = MLO_LINK_UNINITIALIZED; 719 setup_info->num_links--; 720 721 link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 722 if (link_id == INVALID_HW_LINK_ID) { 723 mlo_err("Invalid HW link id for the pdev"); 724 return; 725 } 726 setup_info->valid_link_bitmap &= ~(1 << link_id); 727 728 mlo_debug("Pdev link down grp_id %d link_idx %d num_links %d", 729 grp_id, link_idx, setup_info->num_links); 730 } 731 732 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc, uint8_t grp_id) 733 { 734 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 735 struct mlo_setup_info *setup_info; 736 uint8_t chip_idx; 737 738 if (!mlo_ctx) 739 return; 740 741 if (!psoc) 742 return; 743 744 if (grp_id >= mlo_ctx->total_grp) { 745 mlo_err("Invalid grp id %d, total no of groups %d", 746 grp_id, mlo_ctx->total_grp); 747 return; 748 } 749 750 setup_info = &mlo_ctx->setup_info[grp_id]; 751 752 if (setup_info->num_links) { 753 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 754 mlo_setup_link_down, &grp_id, 755 0, WLAN_MLME_NB_ID); 756 } 757 758 if (!mlo_psoc_get_index_id(psoc, grp_id, &chip_idx, 1)) { 759 mlo_err("Unable to fetch chip idx for psoc id %d grp id %d", 760 psoc->soc_objmgr.psoc_id, 761 grp_id); 762 return; 763 } 764 765 if (!(chip_idx < MAX_MLO_CHIPS)) { 766 mlo_err("Invalid chip index, SoC setup down failed"); 767 return; 768 } 769 770 setup_info->curr_soc_list[chip_idx] = NULL; 771 setup_info->num_soc--; 772 773 mlo_debug("Soc down, mlo group %d num soc %d num links %d", 774 grp_id, setup_info->num_soc, 775 setup_info->num_links); 776 } 777 778 qdf_export_symbol(mlo_setup_update_soc_down); 779 780 static void mlo_dp_ctxt_detach(struct wlan_objmgr_psoc *psoc, 781 uint8_t grp_id, 782 struct cdp_mlo_ctxt *dp_mlo_ctxt) 783 { 784 if (!psoc) 785 return; 786 787 wlan_objmgr_set_dp_mlo_ctx(NULL, grp_id); 788 if (dp_mlo_ctxt) 789 cdp_mlo_ctxt_detach(wlan_psoc_get_dp_handle(psoc), dp_mlo_ctxt); 790 } 791 792 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev, uint8_t grp_id) 793 { 794 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 795 struct mlo_setup_info *setup_info; 796 uint8_t link_idx; 797 struct wlan_objmgr_psoc *soc; 798 uint8_t chip_idx; 799 uint8_t num_soc = 0; 800 801 if (!mlo_ctx) 802 return; 803 804 if (!pdev) 805 return; 806 807 if (grp_id >= mlo_ctx->total_grp) { 808 mlo_err("Invalid grp id %d, total no of groups %d", 809 grp_id, mlo_ctx->total_grp); 810 return; 811 } 812 813 setup_info = &mlo_ctx->setup_info[grp_id]; 814 815 if (!setup_info->num_links) { 816 mlo_err("Delayed response ignore"); 817 return; 818 } 819 820 if (mlo_find_pdev_idx(pdev, &link_idx, grp_id) != QDF_STATUS_SUCCESS) { 821 mlo_info("Failed to find pdev"); 822 return; 823 } 824 825 mlo_debug("Teardown link idx = %d", link_idx); 826 setup_info->state[link_idx] = MLO_LINK_TEARDOWN; 827 828 /* Waiting for teardown on other links */ 829 for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++) 830 if (setup_info->state[link_idx] != MLO_LINK_TEARDOWN) 831 return; 832 833 mlo_debug("Teardown complete"); 834 835 for (chip_idx = 0; chip_idx < setup_info->tot_socs; chip_idx++) { 836 soc = setup_info->curr_soc_list[chip_idx]; 837 if (soc) { 838 num_soc++; 839 cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc), 840 setup_info->dp_handle, 841 false); 842 if (num_soc == setup_info->tot_socs) 843 mlo_dp_ctxt_detach(soc, grp_id, 844 setup_info->dp_handle); 845 } 846 } 847 848 qdf_event_set(&setup_info->event); 849 } 850 851 qdf_export_symbol(mlo_link_teardown_complete); 852 853 static void mlo_force_teardown(uint8_t grp_id) 854 { 855 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 856 struct wlan_objmgr_psoc *soc; 857 struct mlo_setup_info *setup_info; 858 uint8_t link_idx; 859 uint8_t chip_idx; 860 uint8_t num_soc = 0; 861 862 if (!mlo_ctx) 863 return; 864 865 if (grp_id >= mlo_ctx->total_grp) { 866 mlo_err("Invalid grp id %d, total no of groups %d", 867 grp_id, mlo_ctx->total_grp); 868 return; 869 } 870 871 setup_info = &mlo_ctx->setup_info[grp_id]; 872 873 for (link_idx = 0; link_idx < setup_info->tot_links; link_idx++) 874 setup_info->state[link_idx] = MLO_LINK_TEARDOWN; 875 876 for (chip_idx = 0; chip_idx < setup_info->tot_socs; chip_idx++) { 877 soc = setup_info->curr_soc_list[chip_idx]; 878 if (soc) { 879 num_soc++; 880 cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc), 881 setup_info->dp_handle, 882 true); 883 if (num_soc == setup_info->tot_socs) 884 mlo_dp_ctxt_detach(soc, grp_id, 885 setup_info->dp_handle); 886 } 887 } 888 } 889 890 #define MLO_MGR_TEARDOWN_TIMEOUT 3000 891 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc, 892 uint8_t grp_id, 893 uint32_t reason) 894 { 895 struct wlan_lmac_if_tx_ops *tx_ops; 896 QDF_STATUS status; 897 struct mlo_setup_info *setup_info; 898 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 899 900 if (!mlo_ctx) 901 return QDF_STATUS_E_FAILURE; 902 903 if (!psoc) 904 return QDF_STATUS_E_FAILURE; 905 906 if (grp_id >= mlo_ctx->total_grp) { 907 mlo_err("Invalid grp id %d, total no of groups %d", 908 grp_id, mlo_ctx->total_grp); 909 return QDF_STATUS_E_INVAL; 910 } 911 912 setup_info = &mlo_ctx->setup_info[grp_id]; 913 914 mlo_debug("Teardown req with grp_id %d num_soc %d num_link %d", 915 grp_id, setup_info->num_soc, setup_info->num_links); 916 917 if (!setup_info->num_soc) 918 return QDF_STATUS_SUCCESS; 919 920 if (!mlo_check_all_pdev_state(psoc, grp_id, MLO_LINK_TEARDOWN)) 921 return QDF_STATUS_SUCCESS; 922 923 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 924 /* Trigger MLO teardown */ 925 if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) { 926 tx_ops->mops.target_if_mlo_teardown_req( 927 setup_info->pdev_list, 928 setup_info->num_links, 929 reason); 930 } 931 932 if (reason == WMI_MLO_TEARDOWN_REASON_SSR) { 933 /* do not wait for teardown event completion here for SSR */ 934 mlo_dp_ctxt_detach(psoc, grp_id, setup_info->dp_handle); 935 return QDF_STATUS_SUCCESS; 936 } 937 938 status = qdf_wait_for_event_completion( 939 &setup_info->event, 940 MLO_MGR_TEARDOWN_TIMEOUT); 941 942 if (status != QDF_STATUS_SUCCESS) { 943 qdf_debug("Teardown timeout"); 944 mlo_force_teardown(grp_id); 945 } 946 947 return status; 948 } 949 950 qdf_export_symbol(mlo_link_teardown_link); 951 #endif /*WLAN_MLO_MULTI_CHIP*/ 952