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 bool mlo_is_ml_soc(struct wlan_objmgr_psoc *psoc) 29 { 30 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 31 uint8_t chip_idx; 32 33 if (!mlo_ctx) 34 return false; 35 36 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) 37 if (mlo_ctx->setup_info.soc_list[chip_idx] == psoc) 38 return true; 39 40 return false; 41 } 42 43 qdf_export_symbol(mlo_is_ml_soc); 44 45 void mlo_get_soc_list(struct wlan_objmgr_psoc **soc_list) 46 { 47 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 48 uint8_t chip_idx; 49 50 if (!mlo_ctx) { 51 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) 52 soc_list[chip_idx] = NULL; 53 54 return; 55 } 56 57 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) 58 soc_list[chip_idx] = mlo_ctx->setup_info.soc_list[chip_idx]; 59 } 60 61 qdf_export_symbol(mlo_get_soc_list); 62 63 void mlo_cleanup_asserted_soc_setup_info(struct wlan_objmgr_psoc *psoc) 64 { 65 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 66 uint8_t link_idx; 67 struct wlan_objmgr_pdev *pdev; 68 69 if (!mlo_ctx) 70 return; 71 72 if (!mlo_ctx->setup_info.num_links) 73 return; 74 75 if (!psoc) { 76 qdf_info("NULL psoc"); 77 return; 78 } 79 80 for (link_idx = 0; link_idx < MAX_MLO_LINKS; link_idx++) { 81 pdev = mlo_ctx->setup_info.pdev_list[link_idx]; 82 if (pdev) { 83 if (wlan_pdev_get_psoc(pdev) == psoc) { 84 mlo_ctx->setup_info.pdev_list[link_idx] = NULL; 85 mlo_ctx->setup_info.state[link_idx] = 86 MLO_LINK_TEARDOWN; 87 mlo_ctx->setup_info.num_links--; 88 } 89 } 90 } 91 } 92 93 qdf_export_symbol(mlo_cleanup_asserted_soc_setup_info); 94 95 void mlo_setup_update_total_socs(uint8_t tot_socs) 96 { 97 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 98 99 if (!mlo_ctx) 100 return; 101 102 mlo_ctx->setup_info.tot_socs = tot_socs; 103 } 104 105 qdf_export_symbol(mlo_setup_update_total_socs); 106 107 static QDF_STATUS mlo_find_pdev_idx(struct wlan_objmgr_pdev *pdev, 108 uint8_t *link_idx) 109 { 110 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 111 uint8_t idx; 112 113 if (!mlo_ctx) 114 return QDF_STATUS_E_FAILURE; 115 116 if (!link_idx) 117 return QDF_STATUS_E_FAILURE; 118 119 for (idx = 0; idx < mlo_ctx->setup_info.tot_links; idx++) { 120 if (mlo_ctx->setup_info.pdev_list[idx] == pdev) { 121 *link_idx = idx; 122 return QDF_STATUS_SUCCESS; 123 } 124 } 125 126 return QDF_STATUS_E_FAILURE; 127 } 128 129 #define WLAN_SOC_ID_NOT_INITIALIZED -1 130 bool mlo_vdevs_check_single_soc(struct wlan_objmgr_vdev **wlan_vdev_list, 131 uint8_t vdev_count) 132 { 133 int i; 134 uint8_t soc_id = WLAN_SOC_ID_NOT_INITIALIZED; 135 136 for (i = 0; i < vdev_count; i++) { 137 uint8_t vdev_soc_id = wlan_vdev_get_psoc_id(wlan_vdev_list[i]); 138 139 if (i == 0) 140 soc_id = vdev_soc_id; 141 else if (soc_id != vdev_soc_id) 142 return false; 143 } 144 145 return true; 146 } 147 148 qdf_export_symbol(mlo_vdevs_check_single_soc); 149 150 static void mlo_check_state(struct wlan_objmgr_psoc *psoc, 151 void *obj, void *args) 152 { 153 struct wlan_objmgr_pdev *pdev; 154 uint8_t link_idx; 155 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 156 struct mlo_state_params *params = (struct mlo_state_params *)args; 157 158 pdev = (struct wlan_objmgr_pdev *)obj; 159 160 if (!mlo_ctx) 161 return; 162 163 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 164 qdf_info("Failed to find pdev"); 165 return; 166 } 167 168 if (mlo_ctx->setup_info.state[link_idx] != params->check_state) 169 params->link_state_fail = 1; 170 } 171 172 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc, 173 enum MLO_LINK_STATE state) 174 { 175 QDF_STATUS status = QDF_STATUS_E_INVAL; 176 struct mlo_state_params params = {0}; 177 178 params.check_state = state; 179 180 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 181 mlo_check_state, ¶ms, 182 0, WLAN_MLME_NB_ID); 183 184 if (params.link_state_fail) 185 status = QDF_STATUS_E_INVAL; 186 else 187 status = QDF_STATUS_SUCCESS; 188 189 return status; 190 } 191 192 void mlo_setup_init(void) 193 { 194 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 195 196 if (!mlo_ctx) 197 return; 198 199 if (qdf_event_create(&mlo_ctx->setup_info.event) != 200 QDF_STATUS_SUCCESS) { 201 mlo_err("Unable to create teardown event"); 202 } 203 } 204 205 qdf_export_symbol(mlo_setup_init); 206 207 void mlo_setup_deinit(void) 208 { 209 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 210 211 if (!mlo_ctx) 212 return; 213 214 qdf_event_destroy(&mlo_ctx->setup_info.event); 215 } 216 217 qdf_export_symbol(mlo_setup_deinit); 218 219 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc, 220 uint8_t num_links) 221 { 222 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 223 224 if (!mlo_ctx) 225 return; 226 227 mlo_ctx->setup_info.tot_links += num_links; 228 } 229 230 qdf_export_symbol(mlo_setup_update_num_links); 231 232 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc) 233 { 234 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 235 uint8_t chip_idx, tot_socs = 0; 236 237 if (!mlo_ctx || !mlo_ctx->setup_info.tot_socs) 238 return; 239 240 tot_socs = mlo_ctx->setup_info.tot_socs; 241 chip_idx = wlan_psoc_get_id(psoc); 242 243 if (!(chip_idx < MAX_MLO_CHIPS)) { 244 qdf_err("Invalid chip index, SoC setup failed"); 245 return; 246 } 247 248 mlo_ctx->setup_info.soc_list[chip_idx] = psoc; 249 mlo_ctx->setup_info.num_soc++; 250 qdf_debug("soc updated to mld list, id %d num soc %d", 251 chip_idx, mlo_ctx->setup_info.num_soc); 252 253 if (mlo_ctx->setup_info.num_soc != mlo_ctx->setup_info.tot_socs) 254 return; 255 256 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) { 257 struct wlan_objmgr_psoc *tmp_soc = 258 mlo_ctx->setup_info.soc_list[chip_idx]; 259 if (tmp_soc) 260 cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc), 261 mlo_ctx->dp_handle); 262 } 263 264 cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc), 265 mlo_ctx->dp_handle); 266 } 267 268 qdf_export_symbol(mlo_setup_update_soc_ready); 269 270 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev) 271 { 272 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 273 uint8_t link_idx; 274 uint16_t link_id; 275 276 if (!mlo_ctx || !mlo_ctx->setup_info.tot_links) 277 return; 278 279 if (mlo_find_pdev_idx(pdev, &link_idx) == QDF_STATUS_SUCCESS) { 280 qdf_debug("pdev already part of list link idx %d", link_idx); 281 return; 282 } 283 284 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 285 if (!mlo_ctx->setup_info.pdev_list[link_idx]) 286 break; 287 288 if (link_idx >= mlo_ctx->setup_info.tot_links) { 289 qdf_err("Exceeding max total mld links"); 290 return; 291 } 292 293 mlo_ctx->setup_info.pdev_list[link_idx] = pdev; 294 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_SETUP_INIT; 295 mlo_ctx->setup_info.num_links++; 296 297 link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 298 if (link_id == INVALID_HW_LINK_ID) { 299 qdf_err("Invalid HW link id for the pdev"); 300 return; 301 } 302 mlo_ctx->setup_info.valid_link_bitmap |= (1 << link_id); 303 304 qdf_debug("pdev updated to mld link %d num_links %d", 305 link_idx, mlo_ctx->setup_info.num_links); 306 307 qdf_assert_always(link_idx < MAX_MLO_LINKS); 308 309 if (mlo_ctx->setup_info.num_links == mlo_ctx->setup_info.tot_links && 310 mlo_ctx->setup_info.num_soc == mlo_ctx->setup_info.tot_socs) { 311 struct wlan_objmgr_psoc *psoc; 312 struct wlan_lmac_if_tx_ops *tx_ops; 313 QDF_STATUS status; 314 315 psoc = wlan_pdev_get_psoc(pdev); 316 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 317 318 status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc); 319 if (QDF_IS_STATUS_ERROR(status)) { 320 mlo_err("Failed to validate MLO HW link info"); 321 qdf_assert_always(0); 322 } 323 324 qdf_debug("Trigger MLO Setup request"); 325 if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) { 326 tx_ops->mops.target_if_mlo_setup_req( 327 mlo_ctx->setup_info.pdev_list, 328 mlo_ctx->setup_info.num_links, 329 mlo_ctx->setup_info.ml_grp_id); 330 } 331 } 332 } 333 334 qdf_export_symbol(mlo_setup_link_ready); 335 336 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev) 337 { 338 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 339 uint8_t link_idx; 340 341 if (!mlo_ctx) 342 return; 343 344 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 345 if (mlo_ctx->setup_info.pdev_list[link_idx] == pdev) { 346 mlo_ctx->setup_info.state[link_idx] = 347 MLO_LINK_SETUP_DONE; 348 break; 349 } 350 351 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 352 if (mlo_ctx->setup_info.state[link_idx] == MLO_LINK_SETUP_DONE) 353 continue; 354 else 355 break; 356 357 if (link_idx == mlo_ctx->setup_info.tot_links) { 358 struct wlan_objmgr_psoc *psoc; 359 struct wlan_lmac_if_tx_ops *tx_ops; 360 361 psoc = wlan_pdev_get_psoc(pdev); 362 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 363 /* Trigger MLO ready */ 364 if (tx_ops && tx_ops->mops.target_if_mlo_ready) { 365 tx_ops->mops.target_if_mlo_ready( 366 mlo_ctx->setup_info.pdev_list, 367 mlo_ctx->setup_info.num_links); 368 } 369 } 370 } 371 372 qdf_export_symbol(mlo_link_setup_complete); 373 374 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc, 375 void *obj, void *args) 376 { 377 struct wlan_objmgr_pdev *pdev; 378 uint8_t link_idx; 379 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 380 uint16_t link_id; 381 382 pdev = (struct wlan_objmgr_pdev *)obj; 383 384 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 385 qdf_info("Failed to find pdev"); 386 return; 387 } 388 389 mlo_ctx->setup_info.pdev_list[link_idx] = NULL; 390 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_UNINITIALIZED; 391 mlo_ctx->setup_info.num_links--; 392 393 link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 394 if (link_id == INVALID_HW_LINK_ID) { 395 qdf_err("Invalid HW link id for the pdev"); 396 return; 397 } 398 mlo_ctx->setup_info.valid_link_bitmap &= ~(1 << link_id); 399 400 qdf_debug("link down link_idx %d num_links %d", 401 link_idx, mlo_ctx->setup_info.num_links); 402 } 403 404 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc) 405 { 406 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 407 uint8_t chip_idx; 408 409 if (!mlo_ctx) 410 return; 411 412 if (!mlo_ctx->setup_info.num_links) { 413 qdf_debug("Links are already down"); 414 return; 415 } 416 417 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 418 mlo_setup_link_down, NULL, 419 0, WLAN_MLME_NB_ID); 420 421 chip_idx = wlan_psoc_get_id(psoc); 422 423 if (!(chip_idx < MAX_MLO_CHIPS)) { 424 qdf_err("Invalid chip index, SoC setup down failed"); 425 return; 426 } 427 428 mlo_ctx->setup_info.soc_list[chip_idx] = NULL; 429 mlo_ctx->setup_info.num_soc--; 430 431 qdf_debug("Soc down, num soc %d num links %d", 432 mlo_ctx->setup_info.num_soc, 433 mlo_ctx->setup_info.num_links); 434 } 435 436 qdf_export_symbol(mlo_setup_update_soc_down); 437 438 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev) 439 { 440 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 441 uint8_t link_idx; 442 struct wlan_objmgr_psoc *soc; 443 uint8_t chip_idx; 444 445 if (!mlo_ctx) 446 return; 447 448 if (!mlo_ctx->setup_info.num_links) { 449 qdf_err("Delayed response ignore"); 450 return; 451 } 452 453 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 454 qdf_info("Failed to find pdev"); 455 return; 456 } 457 458 qdf_debug("Teardown link idx = %d", link_idx); 459 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN; 460 461 /* Waiting for teardown on other links */ 462 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 463 if (mlo_ctx->setup_info.state[link_idx] != MLO_LINK_TEARDOWN) 464 return; 465 466 qdf_info("Teardown complete"); 467 468 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) { 469 soc = mlo_ctx->setup_info.soc_list[chip_idx]; 470 if (soc) 471 cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc), 472 mlo_ctx->dp_handle); 473 } 474 475 qdf_event_set(&mlo_ctx->setup_info.event); 476 } 477 478 qdf_export_symbol(mlo_link_teardown_complete); 479 480 static void mlo_force_teardown(void) 481 { 482 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 483 struct wlan_objmgr_psoc *soc; 484 uint8_t link_idx = 0; 485 uint8_t chip_idx; 486 487 if (!mlo_ctx) 488 return; 489 490 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 491 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN; 492 493 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) { 494 soc = mlo_ctx->setup_info.soc_list[chip_idx]; 495 if (soc) 496 cdp_soc_mlo_soc_teardown(wlan_psoc_get_dp_handle(soc), 497 mlo_ctx->dp_handle); 498 } 499 } 500 501 #define MLO_MGR_TEARDOWN_TIMEOUT 3000 502 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc, 503 uint32_t reason) 504 { 505 struct wlan_lmac_if_tx_ops *tx_ops; 506 QDF_STATUS status; 507 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 508 509 if (!mlo_ctx) 510 return QDF_STATUS_E_FAILURE; 511 512 qdf_debug("Teardown req with num_soc %d num_link %d", 513 mlo_ctx->setup_info.num_soc, 514 mlo_ctx->setup_info.num_links); 515 516 if (!mlo_ctx->setup_info.num_soc) 517 return QDF_STATUS_SUCCESS; 518 519 if (!mlo_check_all_pdev_state(psoc, MLO_LINK_TEARDOWN)) 520 return QDF_STATUS_SUCCESS; 521 522 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 523 /* Trigger MLO teardown */ 524 if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) { 525 tx_ops->mops.target_if_mlo_teardown_req( 526 mlo_ctx->setup_info.pdev_list, 527 mlo_ctx->setup_info.num_links, 528 reason); 529 } 530 531 if (reason == WMI_MLO_TEARDOWN_REASON_SSR) { 532 /* do not wait for teardown event completion here for SSR */ 533 return QDF_STATUS_SUCCESS; 534 } 535 536 status = qdf_wait_for_event_completion( 537 &mlo_ctx->setup_info.event, 538 MLO_MGR_TEARDOWN_TIMEOUT); 539 if (status != QDF_STATUS_SUCCESS) { 540 qdf_info("Teardown timeout"); 541 mlo_force_teardown(); 542 } 543 544 return status; 545 } 546 547 qdf_export_symbol(mlo_link_teardown_link); 548 #endif /*WLAN_MLO_MULTI_CHIP*/ 549