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 void mlo_setup_init(void) 151 { 152 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 153 154 if (!mlo_ctx) 155 return; 156 157 if (qdf_event_create(&mlo_ctx->setup_info.event) != 158 QDF_STATUS_SUCCESS) { 159 mlo_err("Unable to create teardown event"); 160 } 161 } 162 163 qdf_export_symbol(mlo_setup_init); 164 165 void mlo_setup_deinit(void) 166 { 167 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 168 169 if (!mlo_ctx) 170 return; 171 172 qdf_event_destroy(&mlo_ctx->setup_info.event); 173 } 174 175 qdf_export_symbol(mlo_setup_deinit); 176 177 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc, 178 uint8_t num_links) 179 { 180 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 181 182 if (!mlo_ctx) 183 return; 184 185 mlo_ctx->setup_info.tot_links += num_links; 186 } 187 188 qdf_export_symbol(mlo_setup_update_num_links); 189 190 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc) 191 { 192 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 193 uint8_t chip_idx, tot_socs = 0; 194 195 if (!mlo_ctx || !mlo_ctx->setup_info.tot_socs) 196 return; 197 198 tot_socs = mlo_ctx->setup_info.tot_socs; 199 chip_idx = wlan_psoc_get_id(psoc); 200 201 if (!(chip_idx < MAX_MLO_CHIPS)) { 202 qdf_err("Invalid chip index, SoC setup failed"); 203 return; 204 } 205 206 mlo_ctx->setup_info.soc_list[chip_idx] = psoc; 207 mlo_ctx->setup_info.num_soc++; 208 qdf_debug("soc updated to mld list, id %d num soc %d", 209 chip_idx, mlo_ctx->setup_info.num_soc); 210 211 if (mlo_ctx->setup_info.num_soc != mlo_ctx->setup_info.tot_socs) 212 return; 213 214 for (chip_idx = 0; chip_idx < MAX_MLO_CHIPS; chip_idx++) { 215 struct wlan_objmgr_psoc *tmp_soc = 216 mlo_ctx->setup_info.soc_list[chip_idx]; 217 if (tmp_soc) 218 cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc), 219 mlo_ctx->dp_handle); 220 } 221 222 cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc), 223 mlo_ctx->dp_handle); 224 } 225 226 qdf_export_symbol(mlo_setup_update_soc_ready); 227 228 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev) 229 { 230 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 231 uint8_t link_idx; 232 uint16_t link_id; 233 234 if (!mlo_ctx || !mlo_ctx->setup_info.tot_links) 235 return; 236 237 if (mlo_find_pdev_idx(pdev, &link_idx) == QDF_STATUS_SUCCESS) { 238 qdf_debug("pdev already part of list link idx %d", link_idx); 239 return; 240 } 241 242 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 243 if (!mlo_ctx->setup_info.pdev_list[link_idx]) 244 break; 245 246 if (link_idx >= mlo_ctx->setup_info.tot_links) { 247 qdf_err("Exceeding max total mld links"); 248 return; 249 } 250 251 mlo_ctx->setup_info.pdev_list[link_idx] = pdev; 252 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_SETUP_INIT; 253 mlo_ctx->setup_info.num_links++; 254 255 link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 256 if (link_id == INVALID_HW_LINK_ID) { 257 qdf_err("Invalid HW link id for the pdev"); 258 return; 259 } 260 mlo_ctx->setup_info.valid_link_bitmap |= (1 << link_id); 261 262 qdf_debug("pdev updated to mld link %d num_links %d", 263 link_idx, mlo_ctx->setup_info.num_links); 264 265 qdf_assert_always(link_idx < MAX_MLO_LINKS); 266 267 if (mlo_ctx->setup_info.num_links == mlo_ctx->setup_info.tot_links && 268 mlo_ctx->setup_info.num_soc == mlo_ctx->setup_info.tot_socs) { 269 struct wlan_objmgr_psoc *psoc; 270 struct wlan_lmac_if_tx_ops *tx_ops; 271 QDF_STATUS status; 272 273 psoc = wlan_pdev_get_psoc(pdev); 274 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 275 276 status = wlan_mgmt_rx_reo_validate_mlo_link_info(psoc); 277 if (QDF_IS_STATUS_ERROR(status)) { 278 mlo_err("Failed to validate MLO HW link info"); 279 qdf_assert_always(0); 280 } 281 282 qdf_debug("Trigger MLO Setup request"); 283 if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) { 284 tx_ops->mops.target_if_mlo_setup_req( 285 mlo_ctx->setup_info.pdev_list, 286 mlo_ctx->setup_info.num_links, 287 mlo_ctx->setup_info.ml_grp_id); 288 } 289 } 290 } 291 292 qdf_export_symbol(mlo_setup_link_ready); 293 294 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev) 295 { 296 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 297 uint8_t link_idx; 298 299 if (!mlo_ctx) 300 return; 301 302 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 303 if (mlo_ctx->setup_info.pdev_list[link_idx] == pdev) { 304 mlo_ctx->setup_info.state[link_idx] = 305 MLO_LINK_SETUP_DONE; 306 break; 307 } 308 309 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 310 if (mlo_ctx->setup_info.state[link_idx] == MLO_LINK_SETUP_DONE) 311 continue; 312 else 313 break; 314 315 if (link_idx == mlo_ctx->setup_info.tot_links) { 316 struct wlan_objmgr_psoc *psoc; 317 struct wlan_lmac_if_tx_ops *tx_ops; 318 319 psoc = wlan_pdev_get_psoc(pdev); 320 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 321 /* Trigger MLO ready */ 322 if (tx_ops && tx_ops->mops.target_if_mlo_ready) { 323 tx_ops->mops.target_if_mlo_ready( 324 mlo_ctx->setup_info.pdev_list, 325 mlo_ctx->setup_info.num_links); 326 } 327 } 328 } 329 330 qdf_export_symbol(mlo_link_setup_complete); 331 332 static void mlo_setup_link_down(struct wlan_objmgr_psoc *psoc, 333 void *obj, void *args) 334 { 335 struct wlan_objmgr_pdev *pdev; 336 uint8_t link_idx; 337 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 338 uint16_t link_id; 339 340 pdev = (struct wlan_objmgr_pdev *)obj; 341 342 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 343 qdf_info("Failed to find pdev"); 344 return; 345 } 346 347 mlo_ctx->setup_info.pdev_list[link_idx] = NULL; 348 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_UNINITIALIZED; 349 mlo_ctx->setup_info.num_links--; 350 351 link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 352 if (link_id == INVALID_HW_LINK_ID) { 353 qdf_err("Invalid HW link id for the pdev"); 354 return; 355 } 356 mlo_ctx->setup_info.valid_link_bitmap &= ~(1 << link_id); 357 358 qdf_debug("link down link_idx %d num_links %d", 359 link_idx, mlo_ctx->setup_info.num_links); 360 } 361 362 void mlo_setup_update_soc_down(struct wlan_objmgr_psoc *psoc) 363 { 364 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 365 uint8_t chip_idx; 366 367 if (!mlo_ctx) 368 return; 369 370 if (!mlo_ctx->setup_info.num_links) { 371 qdf_debug("Links are already down"); 372 return; 373 } 374 375 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 376 mlo_setup_link_down, NULL, 377 0, WLAN_MLME_NB_ID); 378 379 chip_idx = wlan_psoc_get_id(psoc); 380 381 if (!(chip_idx < MAX_MLO_CHIPS)) { 382 qdf_err("Invalid chip index, SoC setup down failed"); 383 return; 384 } 385 386 mlo_ctx->setup_info.soc_list[chip_idx] = NULL; 387 mlo_ctx->setup_info.num_soc--; 388 389 qdf_debug("Soc down, num soc %d num links %d", 390 mlo_ctx->setup_info.num_soc, 391 mlo_ctx->setup_info.num_links); 392 } 393 394 qdf_export_symbol(mlo_setup_update_soc_down); 395 396 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev) 397 { 398 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 399 uint8_t link_idx; 400 401 if (!mlo_ctx) 402 return; 403 404 if (!mlo_ctx->setup_info.num_links) { 405 qdf_err("Delayed response ignore"); 406 return; 407 } 408 409 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 410 qdf_info("Failed to find pdev"); 411 return; 412 } 413 414 qdf_debug("Teardown link idx = %d", link_idx); 415 mlo_ctx->setup_info.pdev_list[link_idx] = NULL; 416 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN; 417 418 if (!mlo_ctx->setup_info.num_links) { 419 qdf_info("Teardown complete"); 420 qdf_event_set(&mlo_ctx->setup_info.event); 421 } 422 } 423 424 qdf_export_symbol(mlo_link_teardown_complete); 425 426 static void mlo_check_state(struct wlan_objmgr_psoc *psoc, 427 void *obj, void *args) 428 { 429 struct wlan_objmgr_pdev *pdev; 430 uint8_t link_idx; 431 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 432 struct mlo_state_params *params = (struct mlo_state_params *)args; 433 434 pdev = (struct wlan_objmgr_pdev *)obj; 435 436 if (!mlo_ctx) 437 return; 438 439 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 440 qdf_info("Failed to find pdev"); 441 return; 442 } 443 444 if (mlo_ctx->setup_info.state[link_idx] != params->check_state) 445 params->link_state_fail = 1; 446 } 447 448 static void mlo_force_teardown(void) 449 { 450 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 451 uint8_t link_idx = 0; 452 453 if (!mlo_ctx) 454 return; 455 456 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 457 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN; 458 } 459 460 QDF_STATUS mlo_check_all_pdev_state(struct wlan_objmgr_psoc *psoc, 461 enum MLO_LINK_STATE state) 462 { 463 QDF_STATUS status = QDF_STATUS_E_INVAL; 464 struct mlo_state_params params = {0}; 465 466 params.check_state = state; 467 468 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 469 mlo_check_state, ¶ms, 470 0, WLAN_MLME_NB_ID); 471 472 if (params.link_state_fail) 473 status = QDF_STATUS_E_INVAL; 474 else 475 status = QDF_STATUS_SUCCESS; 476 477 return status; 478 } 479 480 #define MLO_MGR_TEARDOWN_TIMEOUT 3000 481 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc, 482 uint32_t reason) 483 { 484 struct wlan_lmac_if_tx_ops *tx_ops; 485 QDF_STATUS status; 486 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 487 488 if (!mlo_ctx) 489 return QDF_STATUS_E_FAILURE; 490 491 qdf_debug("Teardown req with num_soc %d num_link %d", 492 mlo_ctx->setup_info.num_soc, 493 mlo_ctx->setup_info.num_links); 494 495 if (!mlo_ctx->setup_info.num_soc) 496 return QDF_STATUS_SUCCESS; 497 498 if (!mlo_check_all_pdev_state(psoc, MLO_LINK_TEARDOWN)) 499 return QDF_STATUS_SUCCESS; 500 501 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 502 /* Trigger MLO teardown */ 503 if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) { 504 tx_ops->mops.target_if_mlo_teardown_req( 505 mlo_ctx->setup_info.pdev_list, 506 mlo_ctx->setup_info.num_links, 507 reason); 508 } 509 510 if (reason == WMI_MLO_TEARDOWN_REASON_SSR) { 511 /* do not wait for teardown event completion here for SSR */ 512 return QDF_STATUS_SUCCESS; 513 } 514 515 status = qdf_wait_for_event_completion( 516 &mlo_ctx->setup_info.event, 517 MLO_MGR_TEARDOWN_TIMEOUT); 518 if (status != QDF_STATUS_SUCCESS) { 519 qdf_info("Teardown timeout"); 520 mlo_force_teardown(); 521 } 522 523 return status; 524 } 525 526 qdf_export_symbol(mlo_link_teardown_link); 527 #endif /*WLAN_MLO_MULTI_CHIP*/ 528