1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * DOC: contains MLO manager ap related functionality 20 */ 21 #include <qdf_module.h> 22 #include "wlan_objmgr_vdev_obj.h" 23 #include "wlan_mlo_mgr_ap.h" 24 #include <wlan_mlo_mgr_cmn.h> 25 #include <wlan_mlo_mgr_main.h> 26 #include <wlan_utility.h> 27 #ifdef WLAN_MLO_MULTI_CHIP 28 #include "cdp_txrx_mlo.h" 29 #endif 30 #include "wlan_mlo_mgr_peer.h" 31 32 #ifdef WLAN_MLO_MULTI_CHIP 33 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 34 uint8_t link_id, 35 uint16_t vdev_count) 36 { 37 struct wlan_mlo_dev_context *dev_ctx; 38 uint8_t pr_vdev_ids[WLAN_UMAC_MLO_MAX_VDEVS] = { CDP_INVALID_VDEV_ID }; 39 struct wlan_objmgr_psoc *psoc; 40 int i; 41 42 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 43 mlo_err("Invalid input"); 44 return false; 45 } 46 47 psoc = wlan_vdev_get_psoc(vdev); 48 if (!psoc) 49 return false; 50 51 dev_ctx = vdev->mlo_dev_ctx; 52 53 if (!vdev->vdev_objmgr.mlo_bridge_vdev) { 54 wlan_vdev_set_link_id(vdev, link_id); 55 wlan_vdev_mlme_set_mlo_vdev(vdev); 56 57 /* 58 * every link will trigger mlo_ap_vdev_attach, 59 * and they should provide the same vdev_count. 60 */ 61 mlo_dev_lock_acquire(dev_ctx); 62 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 63 mlo_dev_lock_release(dev_ctx); 64 } 65 66 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 67 if (dev_ctx->wlan_vdev_list[i]) 68 pr_vdev_ids[i] = wlan_vdev_get_id(dev_ctx->wlan_vdev_list[i]); 69 } 70 71 /* reset the vdev id list */ 72 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) 73 pr_vdev_ids[i] = CDP_INVALID_VDEV_ID; 74 75 /* update the bridge vaps in partner list*/ 76 for (i = 0; i < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS; i++) { 77 if (dev_ctx->wlan_bridge_vdev_list[i]) 78 pr_vdev_ids[i] = wlan_vdev_get_id( 79 dev_ctx->wlan_bridge_vdev_list[i]); 80 } 81 82 return true; 83 } 84 #else 85 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 86 uint8_t link_id, 87 uint16_t vdev_count) 88 { 89 struct wlan_mlo_dev_context *dev_ctx; 90 91 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 92 mlo_err("Invalid input"); 93 return false; 94 } 95 96 dev_ctx = vdev->mlo_dev_ctx; 97 wlan_vdev_set_link_id(vdev, link_id); 98 wlan_vdev_mlme_set_mlo_vdev(vdev); 99 100 /* 101 * every link will trigger mlo_ap_vdev_attach, 102 * and they should provide the same vdev_count. 103 */ 104 mlo_dev_lock_acquire(dev_ctx); 105 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 106 mlo_dev_lock_release(dev_ctx); 107 108 return true; 109 } 110 #endif 111 112 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) 113 void mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev *vdev, 114 uint16_t *vdev_count, 115 struct wlan_objmgr_vdev **wlan_bridge_vdev_list) 116 { 117 struct wlan_mlo_dev_context *dev_ctx; 118 int i; 119 QDF_STATUS status; 120 121 *vdev_count = 0; 122 123 if (!vdev || !vdev->mlo_dev_ctx) { 124 mlo_err("Invalid input"); 125 return; 126 } 127 128 dev_ctx = vdev->mlo_dev_ctx; 129 130 mlo_dev_lock_acquire(dev_ctx); 131 *vdev_count = 0; 132 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_bridge_vdev_list); i++) { 133 if (dev_ctx->wlan_bridge_vdev_list[i]) { 134 status = wlan_objmgr_vdev_try_get_ref( 135 dev_ctx->wlan_bridge_vdev_list[i], 136 WLAN_MLO_MGR_ID); 137 if (QDF_IS_STATUS_ERROR(status)) 138 break; 139 wlan_bridge_vdev_list[*vdev_count] = 140 dev_ctx->wlan_bridge_vdev_list[i]; 141 (*vdev_count) += 1; 142 } 143 } 144 mlo_dev_lock_release(dev_ctx); 145 } 146 147 QDF_STATUS mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context *mld_ctx, 148 uint16_t *vdev_count) 149 { 150 int i; 151 152 *vdev_count = 0; 153 154 if (!mld_ctx) { 155 mlo_err("Invalid input"); 156 return QDF_STATUS_E_NULL_VALUE; 157 } 158 159 mlo_dev_lock_acquire(mld_ctx); 160 *vdev_count = 0; 161 for (i = 0; i < QDF_ARRAY_SIZE(mld_ctx->wlan_bridge_vdev_list); i++) { 162 if (mld_ctx->wlan_bridge_vdev_list[i]) 163 (*vdev_count) += 1; 164 } 165 mlo_dev_lock_release(mld_ctx); 166 167 return QDF_STATUS_SUCCESS; 168 } 169 170 void mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev *vdev, 171 uint16_t *vdev_count, 172 struct wlan_objmgr_vdev **wlan_vdev_list) 173 { 174 struct wlan_mlo_dev_context *dev_ctx; 175 int i; 176 QDF_STATUS status; 177 178 *vdev_count = 0; 179 180 if (!vdev || !vdev->mlo_dev_ctx) { 181 mlo_err("Invalid input"); 182 return; 183 } 184 185 dev_ctx = vdev->mlo_dev_ctx; 186 187 mlo_dev_lock_acquire(dev_ctx); 188 *vdev_count = 0; 189 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 190 if (dev_ctx->wlan_vdev_list[i]) { 191 status = wlan_objmgr_vdev_try_get_ref( 192 dev_ctx->wlan_vdev_list[i], 193 WLAN_MLO_MGR_ID); 194 if (QDF_IS_STATUS_ERROR(status)) 195 break; 196 wlan_vdev_list[*vdev_count] = 197 dev_ctx->wlan_vdev_list[i]; 198 (*vdev_count) += 1; 199 } 200 } 201 mlo_dev_lock_release(dev_ctx); 202 } 203 #endif 204 205 void mlo_peer_get_vdev_list(struct wlan_objmgr_peer *peer, 206 uint16_t *vdev_count, 207 struct wlan_objmgr_vdev **wlan_vdev_list) 208 { 209 struct wlan_mlo_link_peer_entry *peer_entry; 210 struct wlan_objmgr_peer *link_peer; 211 int i; 212 QDF_STATUS status; 213 214 *vdev_count = 0; 215 216 if (!peer) { 217 mlo_err("Invalid input"); 218 return; 219 } 220 221 mlo_peer_lock_acquire(peer->mlo_peer_ctx); 222 223 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 224 peer_entry = &peer->mlo_peer_ctx->peer_list[i]; 225 link_peer = peer_entry->link_peer; 226 if (!link_peer) 227 continue; 228 229 status = wlan_objmgr_vdev_try_get_ref( 230 wlan_peer_get_vdev(link_peer), 231 WLAN_MLO_MGR_ID); 232 if (QDF_IS_STATUS_ERROR(status)) 233 break; 234 235 wlan_vdev_list[*vdev_count] = 236 wlan_peer_get_vdev(link_peer); 237 (*vdev_count) += 1; 238 } 239 240 mlo_peer_lock_release(peer->mlo_peer_ctx); 241 } 242 243 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev, 244 uint16_t *vdev_count, 245 struct wlan_objmgr_vdev **wlan_vdev_list) 246 { 247 struct wlan_mlo_dev_context *dev_ctx; 248 int i; 249 QDF_STATUS status; 250 251 *vdev_count = 0; 252 253 if (!vdev || !vdev->mlo_dev_ctx) { 254 mlo_err("Invalid input"); 255 return; 256 } 257 258 dev_ctx = vdev->mlo_dev_ctx; 259 260 mlo_dev_lock_acquire(dev_ctx); 261 *vdev_count = 0; 262 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 263 if (dev_ctx->wlan_vdev_list[i] && 264 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) { 265 status = wlan_objmgr_vdev_try_get_ref( 266 dev_ctx->wlan_vdev_list[i], 267 WLAN_MLO_MGR_ID); 268 if (QDF_IS_STATUS_ERROR(status)) 269 break; 270 wlan_vdev_list[*vdev_count] = 271 dev_ctx->wlan_vdev_list[i]; 272 (*vdev_count) += 1; 273 } 274 } 275 mlo_dev_lock_release(dev_ctx); 276 } 277 278 void mlo_ap_get_active_vdev_list(struct wlan_objmgr_vdev *vdev, 279 uint16_t *vdev_count, 280 struct wlan_objmgr_vdev **wlan_vdev_list) 281 { 282 struct wlan_mlo_dev_context *dev_ctx; 283 int i; 284 QDF_STATUS status; 285 struct wlan_objmgr_vdev *partner_vdev = NULL; 286 287 *vdev_count = 0; 288 289 if (!vdev || !vdev->mlo_dev_ctx) { 290 mlo_err("Invalid input"); 291 return; 292 } 293 294 dev_ctx = vdev->mlo_dev_ctx; 295 296 mlo_dev_lock_acquire(dev_ctx); 297 *vdev_count = 0; 298 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 299 partner_vdev = dev_ctx->wlan_vdev_list[i]; 300 if (partner_vdev && 301 wlan_vdev_mlme_is_mlo_ap(partner_vdev)) { 302 if (wlan_vdev_chan_config_valid(partner_vdev) != 303 QDF_STATUS_SUCCESS) 304 continue; 305 306 status = wlan_objmgr_vdev_try_get_ref(partner_vdev, 307 WLAN_MLO_MGR_ID); 308 if (QDF_IS_STATUS_ERROR(status)) 309 break; 310 wlan_vdev_list[*vdev_count] = partner_vdev; 311 (*vdev_count) += 1; 312 } 313 } 314 mlo_dev_lock_release(dev_ctx); 315 } 316 317 void mlo_ap_get_partner_vdev_list_from_mld( 318 struct wlan_objmgr_vdev *vdev, 319 uint16_t *vdev_count, 320 struct wlan_objmgr_vdev **wlan_vdev_list) 321 { 322 struct wlan_mlo_dev_context *dev_ctx; 323 int i; 324 QDF_STATUS status; 325 326 *vdev_count = 0; 327 328 if (!vdev || !vdev->mlo_dev_ctx) { 329 mlo_err("Invalid input"); 330 return; 331 } 332 333 dev_ctx = vdev->mlo_dev_ctx; 334 335 mlo_dev_lock_acquire(dev_ctx); 336 *vdev_count = 0; 337 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 338 if (dev_ctx->wlan_vdev_list[i] && 339 (QDF_SAP_MODE == 340 wlan_vdev_mlme_get_opmode(dev_ctx->wlan_vdev_list[i]))) { 341 status = wlan_objmgr_vdev_try_get_ref( 342 dev_ctx->wlan_vdev_list[i], 343 WLAN_MLO_MGR_ID); 344 if (QDF_IS_STATUS_ERROR(status)) 345 break; 346 wlan_vdev_list[*vdev_count] = 347 dev_ctx->wlan_vdev_list[i]; 348 (*vdev_count) += 1; 349 } 350 } 351 mlo_dev_lock_release(dev_ctx); 352 } 353 354 /** 355 * mlo_ap_vdev_is_start_resp_rcvd() - Is start response received on this vdev 356 * @vdev: vdev pointer 357 * 358 * Return: SUCCESS if start response is received, ERROR otherwise. 359 */ 360 static QDF_STATUS mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev *vdev) 361 { 362 enum wlan_vdev_state state; 363 364 if (!vdev) { 365 mlme_err("vdev is null"); 366 return QDF_STATUS_E_FAILURE; 367 } 368 369 if (!wlan_vdev_mlme_is_mlo_ap(vdev)) 370 return QDF_STATUS_E_FAILURE; 371 372 state = wlan_vdev_mlme_get_state(vdev); 373 if ((state == WLAN_VDEV_S_UP) || 374 (state == WLAN_VDEV_S_DFS_CAC_WAIT) || 375 (state == WLAN_VDEV_S_SUSPEND)) 376 return QDF_STATUS_SUCCESS; 377 378 return QDF_STATUS_E_FAILURE; 379 } 380 381 uint16_t wlan_mlo_ap_get_active_links(struct wlan_objmgr_vdev *vdev) 382 { 383 uint16_t vdev_count = 0; 384 struct wlan_mlo_dev_context *dev_ctx; 385 int i; 386 387 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 388 mlo_err("Invalid input"); 389 return vdev_count; 390 } 391 392 dev_ctx = vdev->mlo_dev_ctx; 393 394 mlo_dev_lock_acquire(dev_ctx); 395 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 396 if (dev_ctx->wlan_vdev_list[i] && QDF_IS_STATUS_SUCCESS( 397 mlo_ap_vdev_is_start_resp_rcvd(dev_ctx->wlan_vdev_list[i]))) 398 vdev_count++; 399 } 400 401 mlo_dev_lock_release(dev_ctx); 402 403 return vdev_count; 404 } 405 406 /** 407 * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up 408 * @vdev: vdev pointer 409 * 410 * Return: true if given ap is allowed to up, false otherwise. 411 */ 412 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev) 413 { 414 uint16_t vdev_count = 0; 415 bool up_allowed = false; 416 struct wlan_mlo_dev_context *dev_ctx; 417 418 if (!vdev) { 419 mlo_err("Invalid input"); 420 return up_allowed; 421 } 422 423 dev_ctx = vdev->mlo_dev_ctx; 424 425 vdev_count = wlan_mlo_ap_get_active_links(vdev); 426 if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs) 427 up_allowed = true; 428 429 return up_allowed; 430 } 431 432 /** 433 * mlo_pre_link_up() - Carry out preparation before bringing up the link 434 * @vdev: vdev pointer 435 * 436 * Return: true if preparation is done successfully 437 */ 438 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev) 439 { 440 if (!vdev) { 441 mlo_err("vdev is NULL"); 442 return false; 443 } 444 445 if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) && 446 (wlan_vdev_mlme_get_substate(vdev) == 447 WLAN_VDEV_SS_MLO_SYNC_WAIT)) 448 return true; 449 450 return false; 451 } 452 453 /** 454 * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not. 455 * If it is allowed, for every link in the 456 * WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver 457 * event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE. 458 * 459 * This function is triggered once a link gets start response or enters 460 * WLAN_VDEV_SS_MLO_SYNC_WAIT state 461 * 462 * @vdev: vdev pointer 463 * 464 * Return: true if MLO_SYNC_COMPLETE is posted, else false 465 */ 466 static bool mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev) 467 { 468 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; 469 struct wlan_mlo_dev_context *mld_ctx = NULL; 470 uint16_t num_links = 0; 471 uint8_t i; 472 uint8_t idx; 473 enum wlan_vdev_state state; 474 enum wlan_vdev_state substate; 475 476 477 if (!vdev || !vdev->mlo_dev_ctx) { 478 mlo_err("Invalid input"); 479 return false; 480 } 481 482 if (wlan_vdev_is_up(vdev) == QDF_STATUS_SUCCESS) 483 return true; 484 485 mld_ctx = vdev->mlo_dev_ctx; 486 /* 487 * The last vdev in MLD to receive start response is responsible for 488 * dispatching MLO_SYNC_COMPLETE event all the partner vdevs and then to 489 * self. 490 * 491 * If vdev_up_bmap is set, then return. 492 */ 493 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 494 if (idx == MLO_INVALID_LINK_IDX) 495 return false; 496 497 if (wlan_util_map_index_is_set(mld_ctx->ap_ctx->mlo_vdev_up_bmap, 498 idx)) { 499 mlo_debug("Bmap is set for idx:%u mld_addr " QDF_MAC_ADDR_FMT, 500 idx, QDF_MAC_ADDR_REF(mld_ctx->mld_addr.bytes)); 501 return false; 502 } 503 504 mlo_ap_lock_acquire(vdev->mlo_dev_ctx->ap_ctx); 505 state = wlan_vdev_mlme_get_state(vdev); 506 substate = wlan_vdev_mlme_get_substate(vdev); 507 if (state == WLAN_VDEV_S_UP && substate == WLAN_VDEV_SS_MLO_SYNC_WAIT) { 508 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 509 if (idx == MLO_INVALID_LINK_IDX) { 510 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx); 511 return false; 512 } 513 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_up_bmap, 514 idx, 1); 515 mlo_debug("Setting Bmap for idx:%u mld_addr " QDF_MAC_ADDR_FMT, 516 idx, QDF_MAC_ADDR_REF(mld_ctx->mld_addr.bytes)); 517 } 518 519 if (!mlo_is_ap_vdev_up_allowed(vdev)) { 520 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx); 521 return false; 522 } 523 524 mlo_ap_get_vdev_list(vdev, &num_links, vdev_list); 525 if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) { 526 mlo_err("Invalid number of VDEVs under AP-MLD"); 527 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx); 528 return false; 529 } 530 531 for (i = 0; i < num_links; i++) { 532 if (mlo_pre_link_up(vdev_list[i])) { 533 if (vdev_list[i] == vdev) { 534 mlo_release_vdev_ref(vdev_list[i]); 535 continue; 536 } 537 538 idx = mlo_get_link_vdev_ix(mld_ctx, vdev_list[i]); 539 if (idx == MLO_INVALID_LINK_IDX) { 540 mlo_release_vdev_ref(vdev_list[i]); 541 continue; 542 } 543 544 if (wlan_util_map_index_is_set( 545 vdev->mlo_dev_ctx->ap_ctx->mlo_vdev_up_bmap, 546 idx)) 547 wlan_vdev_mlme_sm_deliver_evt( 548 vdev_list[i], 549 WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE, 550 0, NULL); 551 } 552 /* Release ref taken as part of mlo_ap_get_vdev_list */ 553 mlo_release_vdev_ref(vdev_list[i]); 554 } 555 556 /* Clear up bmap for this vdev as it is moving to UP_ACTIVE state */ 557 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 558 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_up_bmap, idx, 0); 559 560 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx); 561 return true; 562 } 563 564 bool mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev) 565 { 566 return mlo_handle_link_ready(vdev); 567 } 568 569 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev) 570 { 571 mlo_handle_link_ready(vdev); 572 } 573 574 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev) 575 { 576 struct wlan_mlo_dev_context *dev_ctx; 577 578 if (!vdev || !vdev->mlo_dev_ctx) { 579 mlo_err("Invalid input"); 580 return; 581 } 582 583 dev_ctx = vdev->mlo_dev_ctx; 584 585 mlo_dev_lock_acquire(dev_ctx); 586 dev_ctx->ap_ctx->num_ml_vdevs--; 587 mlo_dev_lock_release(dev_ctx); 588 589 wlan_vdev_mlme_clear_mlo_vdev(vdev); 590 } 591 592 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev) 593 { 594 mlo_ap_vdev_detach(vdev); 595 } 596 597 QDF_STATUS 598 mlo_ap_update_max_ml_peer_ids(uint32_t pdev_id, uint32_t max_ml_peer_ids) 599 { 600 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 601 uint16_t max_mlo_peer_id_stale; 602 603 max_mlo_peer_id_stale = mlo_mgr_ctx->max_mlo_peer_id; 604 605 ml_peerid_lock_acquire(mlo_mgr_ctx); 606 607 /* Reset the value to default if max_ml_peer_ids received is "0" */ 608 mlo_mgr_ctx->max_mlo_peer_id = max_ml_peer_ids ? 609 max_ml_peer_ids : MAX_MLO_PEER_ID; 610 611 mlo_info("max_ml_peer_ids update from: %d to: %d for pdev: %d", 612 max_mlo_peer_id_stale, 613 mlo_mgr_ctx->max_mlo_peer_id, pdev_id); 614 615 mlo_info("max_peer support from target obtained :%d", max_ml_peer_ids); 616 617 ml_peerid_lock_release(mlo_mgr_ctx); 618 619 return QDF_STATUS_SUCCESS; 620 } 621 622 qdf_export_symbol(mlo_ap_update_max_ml_peer_ids); 623 624 uint16_t mlo_ap_ml_peerid_alloc(void) 625 { 626 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 627 uint16_t i; 628 uint16_t mlo_peer_id; 629 630 ml_peerid_lock_acquire(mlo_ctx); 631 mlo_peer_id = mlo_ctx->last_mlo_peer_id; 632 for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) { 633 mlo_peer_id = (mlo_peer_id + 1) % mlo_ctx->max_mlo_peer_id; 634 635 if (!mlo_peer_id) 636 continue; 637 638 if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap)) 639 continue; 640 641 qdf_set_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap); 642 break; 643 } 644 mlo_ctx->last_mlo_peer_id = mlo_peer_id; 645 ml_peerid_lock_release(mlo_ctx); 646 647 if (i == mlo_ctx->max_mlo_peer_id) 648 return MLO_INVALID_PEER_ID; 649 650 mlo_debug(" ML peer id %d is allocated", mlo_peer_id); 651 652 return mlo_peer_id; 653 } 654 655 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE 656 void mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context *ml_dev, 657 uint16_t mlo_peer_id) 658 { 659 /* Free the bitmap for ptqm migration */ 660 if (qdf_test_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap)) 661 qdf_clear_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap); 662 } 663 #endif 664 665 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id) 666 { 667 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 668 669 if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) { 670 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 671 return; 672 } 673 674 if ((mlo_peer_id > mlo_ctx->max_mlo_peer_id) || 675 (mlo_peer_id > MAX_MLO_PEER_ID)) { 676 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 677 QDF_BUG(0); 678 return; 679 } 680 681 ml_peerid_lock_acquire(mlo_ctx); 682 if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap)) 683 qdf_clear_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap); 684 685 ml_peerid_lock_release(mlo_ctx); 686 687 mlo_debug(" ML peer id %d is freed", mlo_peer_id); 688 } 689 690 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev) 691 { 692 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 693 uint8_t idx; 694 695 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 696 return; 697 698 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 699 if (idx == MLO_INVALID_LINK_IDX) 700 return; 701 702 mlo_debug("Quiet set for PSOC:%d vdev:%d", 703 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 704 wlan_vdev_get_id(vdev)); 705 706 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 707 idx, 1); 708 } 709 710 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev) 711 { 712 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 713 uint8_t idx; 714 715 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 716 return; 717 718 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 719 if (idx == MLO_INVALID_LINK_IDX) 720 return; 721 722 mlo_debug("Quiet clear for PSOC:%d vdev:%d", 723 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 724 wlan_vdev_get_id(vdev)); 725 726 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 727 idx, 0); 728 } 729 730 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev) 731 { 732 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 733 734 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 735 return false; 736 737 return wlan_util_map_is_any_index_set( 738 mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 739 sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap)); 740 } 741 742 QDF_STATUS 743 mlo_peer_create_get_frm_buf( 744 struct wlan_mlo_peer_context *ml_peer, 745 struct peer_create_notif_s *peer_create, 746 qdf_nbuf_t frm_buf) 747 { 748 if (wlan_mlo_peer_is_nawds(ml_peer) || 749 wlan_mlo_peer_is_mesh(ml_peer)) { 750 peer_create->frm_buf = NULL; 751 return QDF_STATUS_SUCCESS; 752 } 753 754 if (!frm_buf) 755 return QDF_STATUS_E_FAILURE; 756 757 peer_create->frm_buf = qdf_nbuf_clone(frm_buf); 758 if (!peer_create->frm_buf) 759 return QDF_STATUS_E_NOMEM; 760 761 return QDF_STATUS_SUCCESS; 762 } 763 764 #ifdef UMAC_SUPPORT_MLNAWDS 765 void mlo_peer_populate_nawds_params( 766 struct wlan_mlo_peer_context *ml_peer, 767 struct mlo_partner_info *ml_info) 768 { 769 uint8_t i; 770 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00, 771 0x00, 0x00, 0x00}; 772 struct mlnawds_config nawds_config; 773 774 mlo_peer_lock_acquire(ml_peer); 775 ml_peer->is_nawds_ml_peer = false; 776 for (i = 0; i < ml_info->num_partner_links; i++) { 777 nawds_config = ml_info->partner_link_info[i].nawds_config; 778 /* 779 * if ml_info->partner_link_info[i].nawds_config has valid 780 * config(check for non-null mac or non-0 caps), then mark 781 * ml_peer's is_nawds_ml_peer true & copy the config 782 */ 783 if ((nawds_config.caps) || 784 (qdf_mem_cmp(null_mac, 785 nawds_config.mac, 786 sizeof(null_mac)))) { 787 ml_peer->is_nawds_ml_peer = true; 788 ml_peer->nawds_config[i] = nawds_config; 789 } 790 } 791 mlo_peer_lock_release(ml_peer); 792 } 793 #endif 794 795 #ifdef MESH_MODE_SUPPORT 796 void mlo_peer_populate_mesh_params( 797 struct wlan_mlo_peer_context *ml_peer, 798 struct mlo_partner_info *ml_info) 799 { 800 uint8_t i; 801 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0}; 802 struct mlnawds_config mesh_config; 803 804 mlo_peer_lock_acquire(ml_peer); 805 ml_peer->is_mesh_ml_peer = false; 806 for (i = 0; i < ml_info->num_partner_links; i++) { 807 mesh_config = ml_info->partner_link_info[i].mesh_config; 808 /* 809 * if ml_info->partner_link_info[i].mesh_config has valid 810 * config(check for non-null mac or non-0 caps), then mark 811 * ml_peer's is_mesh_ml_peer true & copy the config 812 */ 813 if ((mesh_config.caps) || 814 (qdf_mem_cmp(null_mac, 815 mesh_config.mac, 816 sizeof(null_mac)))) { 817 ml_peer->is_mesh_ml_peer = true; 818 ml_peer->mesh_config[i] = mesh_config; 819 } 820 } 821 mlo_peer_lock_release(ml_peer); 822 } 823 #endif 824