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 "wlan_mlo_mgr_cmn.h" 22 #include "wlan_mlo_mgr_main.h" 23 #include "wlan_mlo_mgr_sta.h" 24 #ifdef WLAN_MLO_MULTI_CHIP 25 #include "wlan_lmac_if_def.h" 26 #endif 27 #include "wlan_serialization_api.h" 28 #include <target_if_mlo_mgr.h> 29 #include <cdp_txrx_cmn.h> 30 #include <wlan_cfg.h> 31 32 void mlo_get_link_information(struct qdf_mac_addr *mld_addr, 33 struct mlo_link_info *info) 34 { 35 /* Pass the partner link information*/ 36 } 37 38 void is_mlo_all_links_up(struct wlan_mlo_dev_context *mldev) 39 { 40 /* Loop through all the vdev's part of the ML device*/ 41 /* STA: Loop through all the associated vdev status. */ 42 } 43 44 struct wlan_objmgr_vdev *mlo_get_vdev_by_link_id( 45 struct wlan_objmgr_vdev *vdev, 46 uint8_t link_id) 47 { 48 struct wlan_mlo_dev_context *dev_ctx; 49 int i; 50 struct wlan_objmgr_vdev *partner_vdev = NULL; 51 52 if (!vdev || !vdev->mlo_dev_ctx) { 53 mlo_err("Invalid input"); 54 return partner_vdev; 55 } 56 57 dev_ctx = vdev->mlo_dev_ctx; 58 59 mlo_dev_lock_acquire(dev_ctx); 60 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 61 if (dev_ctx->wlan_vdev_list[i] && 62 wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i]) && 63 dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id == 64 link_id) { 65 if (wlan_objmgr_vdev_try_get_ref( 66 dev_ctx->wlan_vdev_list[i], 67 WLAN_MLO_MGR_ID) == 68 QDF_STATUS_SUCCESS) 69 partner_vdev = dev_ctx->wlan_vdev_list[i]; 70 71 break; 72 } 73 } 74 mlo_dev_lock_release(dev_ctx); 75 76 return partner_vdev; 77 } 78 79 void mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev) 80 { 81 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 82 } 83 84 QDF_STATUS mlo_reg_mlme_ext_cb(struct mlo_mgr_context *ctx, 85 struct mlo_mlme_ext_ops *ops) 86 { 87 if (!ctx) 88 return QDF_STATUS_E_FAILURE; 89 90 ctx->mlme_ops = ops; 91 return QDF_STATUS_SUCCESS; 92 } 93 94 QDF_STATUS mlo_unreg_mlme_ext_cb(struct mlo_mgr_context *ctx) 95 { 96 if (!ctx) 97 return QDF_STATUS_E_FAILURE; 98 99 ctx->mlme_ops = NULL; 100 return QDF_STATUS_SUCCESS; 101 } 102 103 QDF_STATUS mlo_mlme_clone_sta_security(struct wlan_objmgr_vdev *vdev, 104 struct wlan_cm_connect_req *req) 105 { 106 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 107 struct vdev_mlme_obj *vdev_mlme; 108 QDF_STATUS status = QDF_STATUS_SUCCESS; 109 110 if (!req || !mlo_ctx || !mlo_ctx->mlme_ops || 111 !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req) 112 return QDF_STATUS_E_FAILURE; 113 114 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 115 if (!vdev_mlme) 116 return QDF_STATUS_E_FAILURE; 117 118 if (mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param) { 119 status = 120 mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param( 121 vdev_mlme, req); 122 } 123 124 return status; 125 } 126 127 QDF_STATUS mlo_mlme_sta_op_class(struct wlan_objmgr_vdev *vdev, 128 uint8_t *ml_ie) 129 { 130 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 131 struct vdev_mlme_obj *vdev_mlme; 132 QDF_STATUS status = QDF_STATUS_SUCCESS; 133 134 if (!mlo_ctx || !mlo_ctx->mlme_ops || 135 !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req) 136 return QDF_STATUS_E_FAILURE; 137 138 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 139 if (!vdev_mlme) 140 return QDF_STATUS_E_FAILURE; 141 142 if (mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class) 143 status = 144 mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class( 145 vdev_mlme, ml_ie); 146 147 return status; 148 } 149 150 QDF_STATUS mlo_mlme_validate_conn_req(struct wlan_objmgr_vdev *vdev, 151 void *ext_data) 152 { 153 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 154 struct vdev_mlme_obj *vdev_mlme; 155 QDF_STATUS status; 156 157 if (!mlo_ctx || !mlo_ctx->mlme_ops || 158 !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req) 159 return QDF_STATUS_E_FAILURE; 160 161 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 162 if (!vdev_mlme) 163 return QDF_STATUS_E_FAILURE; 164 165 status = 166 mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req(vdev_mlme, 167 ext_data); 168 return status; 169 } 170 171 QDF_STATUS mlo_mlme_create_link_vdev(struct wlan_objmgr_vdev *vdev, 172 void *ext_data) 173 { 174 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 175 struct vdev_mlme_obj *vdev_mlme; 176 QDF_STATUS status; 177 178 if (!mlo_ctx || !mlo_ctx->mlme_ops || 179 !mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev) 180 return QDF_STATUS_E_FAILURE; 181 182 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 183 if (!vdev_mlme) 184 return QDF_STATUS_E_FAILURE; 185 186 status = 187 mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev(vdev_mlme, 188 ext_data); 189 return status; 190 } 191 192 void mlo_mlme_peer_create(struct wlan_objmgr_vdev *vdev, 193 struct wlan_mlo_peer_context *ml_peer, 194 struct qdf_mac_addr *addr, 195 qdf_nbuf_t frm_buf) 196 { 197 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 198 199 if (!mlo_ctx || !mlo_ctx->mlme_ops || 200 !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create) 201 return; 202 203 mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create(vdev, ml_peer, 204 addr, frm_buf); 205 } 206 207 void mlo_mlme_bridge_peer_create(struct wlan_objmgr_vdev *vdev, 208 struct wlan_mlo_peer_context *ml_peer, 209 struct qdf_mac_addr *addr, 210 qdf_nbuf_t frm_buf) 211 { 212 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 213 214 if (!mlo_ctx || !mlo_ctx->mlme_ops || 215 !mlo_ctx->mlme_ops->mlo_mlme_ext_bridge_peer_create) 216 return; 217 218 mlo_ctx->mlme_ops->mlo_mlme_ext_bridge_peer_create(vdev, ml_peer, 219 addr, frm_buf); 220 } 221 222 void mlo_mlme_peer_assoc(struct wlan_objmgr_peer *peer) 223 { 224 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 225 226 if (!mlo_ctx || !mlo_ctx->mlme_ops || 227 !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc) 228 return; 229 230 mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc(peer); 231 } 232 233 void mlo_mlme_peer_assoc_fail(struct wlan_objmgr_peer *peer) 234 { 235 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 236 237 if (!mlo_ctx || !mlo_ctx->mlme_ops || 238 !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail) 239 return; 240 241 mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail(peer); 242 } 243 244 void mlo_mlme_peer_delete(struct wlan_objmgr_peer *peer) 245 { 246 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 247 248 if (!mlo_ctx || !mlo_ctx->mlme_ops || 249 !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete) 250 return; 251 252 mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete(peer); 253 } 254 255 void mlo_mlme_peer_assoc_resp(struct wlan_objmgr_peer *peer) 256 { 257 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 258 259 if (!mlo_ctx || !mlo_ctx->mlme_ops || 260 !mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp) 261 return; 262 263 mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp(peer); 264 } 265 266 qdf_nbuf_t mlo_mlme_get_link_assoc_req(struct wlan_objmgr_peer *peer, 267 uint8_t link_ix) 268 { 269 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 270 271 if (!mlo_ctx || !mlo_ctx->mlme_ops || 272 !mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req) 273 return NULL; 274 275 return mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req(peer, link_ix); 276 } 277 278 void mlo_mlme_peer_deauth(struct wlan_objmgr_peer *peer, uint8_t is_disassoc) 279 { 280 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 281 282 if (!mlo_ctx || !mlo_ctx->mlme_ops || 283 !mlo_ctx->mlme_ops->mlo_mlme_ext_deauth) 284 return; 285 286 mlo_ctx->mlme_ops->mlo_mlme_ext_deauth(peer, is_disassoc); 287 } 288 289 #ifdef UMAC_MLO_AUTH_DEFER 290 void mlo_mlme_peer_process_auth(struct mlpeer_auth_params *auth_param) 291 { 292 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 293 294 if (!mlo_ctx || !mlo_ctx->mlme_ops || 295 !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth) 296 return; 297 298 mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth(auth_param); 299 } 300 #endif 301 302 void mlo_mlme_peer_reassoc(struct wlan_objmgr_vdev *vdev, 303 struct wlan_mlo_peer_context *ml_peer, 304 struct qdf_mac_addr *addr, 305 qdf_nbuf_t frm_buf) 306 { 307 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 308 309 if (!mlo_ctx || !mlo_ctx->mlme_ops || 310 !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc) 311 return; 312 313 mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc(vdev, ml_peer, addr, 314 frm_buf); 315 } 316 317 uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *ml_dev, 318 struct wlan_objmgr_vdev *vdev) 319 { 320 uint8_t i; 321 322 mlo_dev_lock_acquire(ml_dev); 323 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 324 if (vdev == ml_dev->wlan_vdev_list[i]) { 325 mlo_dev_lock_release(ml_dev); 326 return i; 327 } 328 } 329 mlo_dev_lock_release(ml_dev); 330 331 return (uint8_t)-1; 332 } 333 334 #ifdef WLAN_MLO_MULTI_CHIP 335 int8_t wlan_mlo_get_max_num_links(uint8_t grp_id) 336 { 337 struct mlo_mgr_context *mlo_ctx; 338 339 mlo_ctx = wlan_objmgr_get_mlo_ctx(); 340 if (!mlo_ctx) 341 return WLAN_MLO_INVALID_NUM_LINKS; 342 343 if (grp_id >= mlo_ctx->total_grp) { 344 mlo_err("Invalid grp id %d, total no of groups %d", 345 grp_id, mlo_ctx->total_grp); 346 return WLAN_MLO_INVALID_NUM_LINKS; 347 } 348 349 return (mlo_ctx->setup_info[grp_id].tot_socs * 350 WLAN_MAX_MLO_LINKS_PER_SOC); 351 } 352 353 int8_t wlan_mlo_get_num_active_links(uint8_t grp_id) 354 { 355 struct mlo_mgr_context *mlo_ctx; 356 357 mlo_ctx = wlan_objmgr_get_mlo_ctx(); 358 359 if (!mlo_ctx) 360 return WLAN_MLO_INVALID_NUM_LINKS; 361 362 if (grp_id >= mlo_ctx->total_grp) { 363 qdf_err("Invalid grp id %d, total no of groups %d", 364 grp_id, mlo_ctx->total_grp); 365 return WLAN_MLO_INVALID_NUM_LINKS; 366 } 367 368 return mlo_ctx->setup_info[grp_id].tot_links; 369 } 370 371 uint16_t wlan_mlo_get_valid_link_bitmap(uint8_t grp_id) 372 { 373 struct mlo_mgr_context *mlo_ctx; 374 375 mlo_ctx = wlan_objmgr_get_mlo_ctx(); 376 if (!mlo_ctx) 377 return 0; 378 379 if (grp_id >= mlo_ctx->total_grp) { 380 qdf_err("Invalid grp id %d, total no of groups %d", 381 grp_id, mlo_ctx->total_grp); 382 return 0; 383 } 384 385 return mlo_ctx->setup_info[grp_id].valid_link_bitmap; 386 } 387 388 uint8_t wlan_mlo_get_psoc_mlo_chip_id(struct wlan_objmgr_psoc *psoc) 389 { 390 struct wlan_lmac_if_tx_ops *tx_ops; 391 uint8_t mlo_chip_id = WLAN_MLO_CHIP_ID_INVALID; 392 393 if (!psoc) { 394 qdf_err("PSOC is NULL"); 395 return mlo_chip_id; 396 } 397 398 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 399 if (tx_ops && tx_ops->mops.get_psoc_mlo_chip_id) 400 mlo_chip_id = tx_ops->mops.get_psoc_mlo_chip_id(psoc); 401 402 return mlo_chip_id; 403 } 404 405 qdf_export_symbol(wlan_mlo_get_psoc_mlo_chip_id); 406 407 uint8_t wlan_mlo_get_psoc_group_id(struct wlan_objmgr_psoc *psoc) 408 { 409 struct wlan_lmac_if_tx_ops *tx_ops; 410 uint8_t ml_grp_id = WLAN_MLO_GROUP_INVALID; 411 412 if (!psoc) { 413 qdf_err("PSOC is NULL"); 414 return -EINVAL; 415 } 416 417 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 418 if (tx_ops && tx_ops->mops.get_psoc_mlo_group_id) 419 ml_grp_id = tx_ops->mops.get_psoc_mlo_group_id(psoc); 420 421 return ml_grp_id; 422 } 423 424 qdf_export_symbol(wlan_mlo_get_psoc_group_id); 425 426 bool wlan_mlo_get_psoc_capable(struct wlan_objmgr_psoc *psoc) 427 { 428 struct target_psoc_info *tgt_hdl; 429 430 if (!psoc) { 431 qdf_err("PSOC is NULL"); 432 return false; 433 } 434 435 tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); 436 if (!tgt_hdl) { 437 target_if_err("target_psoc_info is null"); 438 return false; 439 } 440 441 if ((tgt_hdl->tif_ops) && 442 (tgt_hdl->tif_ops->mlo_capable)) 443 return tgt_hdl->tif_ops->mlo_capable(psoc); 444 445 return false; 446 } 447 448 uint16_t wlan_mlo_get_pdev_hw_link_id(struct wlan_objmgr_pdev *pdev) 449 { 450 struct wlan_objmgr_psoc *psoc; 451 struct wlan_lmac_if_tx_ops *tx_ops; 452 uint16_t hw_link_id = INVALID_HW_LINK_ID; 453 454 psoc = wlan_pdev_get_psoc(pdev); 455 if (psoc) { 456 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 457 if (tx_ops && tx_ops->mops.get_hw_link_id) 458 hw_link_id = tx_ops->mops.get_hw_link_id(pdev); 459 } 460 461 return hw_link_id; 462 } 463 464 qdf_export_symbol(wlan_mlo_get_pdev_hw_link_id); 465 466 static void wlan_pdev_hw_link_iterator(struct wlan_objmgr_psoc *psoc, 467 void *obj, void *arg) 468 { 469 struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg; 470 struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj; 471 uint16_t hw_link_id; 472 uint8_t ml_grp_id; 473 474 if (itr->pdev) 475 return; 476 477 ml_grp_id = wlan_mlo_get_psoc_group_id(psoc); 478 if (ml_grp_id > WLAN_MAX_MLO_GROUPS) 479 return; 480 481 if (ml_grp_id != itr->mlo_grp_id) 482 return; 483 484 hw_link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 485 if (hw_link_id == itr->hw_link_id) { 486 if (wlan_objmgr_pdev_try_get_ref(pdev, itr->dbgid) == 487 QDF_STATUS_SUCCESS) 488 itr->pdev = pdev; 489 } 490 } 491 492 static void wlan_mlo_find_hw_link_id(struct wlan_objmgr_psoc *psoc, 493 void *arg, 494 uint8_t index) 495 { 496 struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg; 497 498 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 499 wlan_pdev_hw_link_iterator, 500 arg, false, itr->dbgid); 501 } 502 503 struct wlan_objmgr_pdev * 504 wlan_mlo_get_pdev_by_hw_link_id(uint16_t hw_link_id, uint8_t ml_grp_id, 505 wlan_objmgr_ref_dbgid refdbgid) 506 { 507 struct hw_link_id_iterator itr; 508 509 itr.hw_link_id = hw_link_id; 510 itr.pdev = NULL; 511 itr.mlo_grp_id = ml_grp_id; 512 itr.dbgid = refdbgid; 513 514 wlan_objmgr_iterate_psoc_list(wlan_mlo_find_hw_link_id, 515 &itr, refdbgid); 516 517 return itr.pdev; 518 } 519 520 qdf_export_symbol(wlan_mlo_get_pdev_by_hw_link_id); 521 #endif /*WLAN_MLO_MULTI_CHIP*/ 522 523 void mlo_get_ml_vdev_list(struct wlan_objmgr_vdev *vdev, 524 uint16_t *vdev_count, 525 struct wlan_objmgr_vdev **wlan_vdev_list) 526 { 527 struct wlan_mlo_dev_context *dev_ctx; 528 int i; 529 QDF_STATUS status; 530 531 *vdev_count = 0; 532 533 if (!vdev || !vdev->mlo_dev_ctx) { 534 mlo_err("Invalid input"); 535 return; 536 } 537 538 dev_ctx = vdev->mlo_dev_ctx; 539 540 mlo_dev_lock_acquire(dev_ctx); 541 *vdev_count = 0; 542 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 543 if (dev_ctx->wlan_vdev_list[i] && 544 wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i])) { 545 status = wlan_objmgr_vdev_try_get_ref( 546 dev_ctx->wlan_vdev_list[i], 547 WLAN_MLO_MGR_ID); 548 if (QDF_IS_STATUS_ERROR(status)) 549 break; 550 wlan_vdev_list[*vdev_count] = 551 dev_ctx->wlan_vdev_list[i]; 552 (*vdev_count) += 1; 553 } 554 } 555 mlo_dev_lock_release(dev_ctx); 556 } 557 558 /** 559 * mlo_link_set_active() - send MLO link set active command 560 * @psoc: PSOC object 561 * @req: MLO link set active request 562 * 563 * Return: QDF_STATUS 564 */ 565 static QDF_STATUS 566 mlo_link_set_active(struct wlan_objmgr_psoc *psoc, 567 struct mlo_link_set_active_req *req) 568 { 569 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 570 struct mlo_link_set_active_param *param = &req->param; 571 QDF_STATUS status; 572 struct mlo_link_set_active_resp rsp_evt; 573 574 if (!psoc) { 575 mlo_err("psoc is null"); 576 return QDF_STATUS_E_NULL_VALUE; 577 } 578 579 mlo_tx_ops = target_if_mlo_get_tx_ops(psoc); 580 if (!mlo_tx_ops) { 581 mlo_err("tx_ops is null!"); 582 return QDF_STATUS_E_NULL_VALUE; 583 } 584 585 if (!mlo_tx_ops->link_set_active) { 586 mlo_err("link_set_active function is null!"); 587 return QDF_STATUS_E_NULL_VALUE; 588 } 589 590 if (req->ctx.validate_set_mlo_link_cb) { 591 status = req->ctx.validate_set_mlo_link_cb(psoc, param); 592 if (QDF_IS_STATUS_ERROR(status)) { 593 qdf_mem_zero(&rsp_evt, sizeof(rsp_evt)); 594 rsp_evt.status = status; 595 if (req->ctx.set_mlo_link_cb) 596 req->ctx.set_mlo_link_cb(req->ctx.vdev, 597 req->ctx.cb_arg, 598 &rsp_evt); 599 return status; 600 } 601 } 602 603 return mlo_tx_ops->link_set_active(psoc, param); 604 } 605 606 /** 607 * mlo_release_ser_link_set_active_cmd() - releases serialization command for 608 * forcing MLO link active/inactive 609 * @vdev: Object manager vdev 610 * 611 * Return: None 612 */ 613 static void 614 mlo_release_ser_link_set_active_cmd(struct wlan_objmgr_vdev *vdev) 615 { 616 struct wlan_serialization_queued_cmd_info cmd = {0}; 617 618 cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK; 619 cmd.requestor = WLAN_UMAC_COMP_MLO_MGR; 620 cmd.cmd_id = 0; 621 cmd.vdev = vdev; 622 623 mlo_debug("release serialization command"); 624 wlan_serialization_remove_cmd(&cmd); 625 } 626 627 /** 628 * mlo_link_set_active_resp_vdev_handler() - vdev handler for mlo link set 629 * active response event. 630 * @psoc: psoc object 631 * @obj: vdev object 632 * @arg: mlo link set active response 633 * 634 * Return: None 635 */ 636 static void 637 mlo_link_set_active_resp_vdev_handler(struct wlan_objmgr_psoc *psoc, 638 void *obj, void *arg) 639 { 640 struct mlo_link_set_active_req *req; 641 struct wlan_objmgr_vdev *vdev = obj; 642 struct mlo_link_set_active_resp *event = arg; 643 644 req = wlan_serialization_get_active_cmd(wlan_vdev_get_psoc(vdev), 645 wlan_vdev_get_id(vdev), 646 WLAN_SER_CMD_SET_MLO_LINK); 647 if (!req) 648 return; 649 650 if (req->ctx.set_mlo_link_cb) 651 req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, event); 652 653 mlo_release_ser_link_set_active_cmd(vdev); 654 } 655 656 QDF_STATUS 657 mlo_process_link_set_active_resp(struct wlan_objmgr_psoc *psoc, 658 struct mlo_link_set_active_resp *event) 659 { 660 wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, 661 mlo_link_set_active_resp_vdev_handler, 662 event, true, WLAN_MLO_MGR_ID); 663 return QDF_STATUS_SUCCESS; 664 } 665 666 /** 667 * mlo_ser_set_link_cb() - Serialization callback function 668 * @cmd: Serialization command info 669 * @reason: Serialization reason for callback execution 670 * 671 * Return: Status of callback execution 672 */ 673 static QDF_STATUS 674 mlo_ser_set_link_cb(struct wlan_serialization_command *cmd, 675 enum wlan_serialization_cb_reason reason) 676 { 677 QDF_STATUS status = QDF_STATUS_SUCCESS; 678 struct wlan_objmgr_vdev *vdev; 679 struct wlan_objmgr_psoc *psoc; 680 struct mlo_link_set_active_req *req; 681 struct mlo_mgr_context *mlo_ctx; 682 683 if (!cmd || !cmd->vdev) 684 return QDF_STATUS_E_FAILURE; 685 686 mlo_ctx = wlan_objmgr_get_mlo_ctx(); 687 if (!mlo_ctx) 688 return QDF_STATUS_E_FAILURE; 689 690 psoc = wlan_vdev_get_psoc(cmd->vdev); 691 if (!psoc) { 692 mlo_err("psoc is NULL, reason: %d", reason); 693 return QDF_STATUS_E_NULL_VALUE; 694 } 695 696 req = cmd->umac_cmd; 697 if (!req) 698 return QDF_STATUS_E_INVAL; 699 700 vdev = cmd->vdev; 701 switch (reason) { 702 case WLAN_SER_CB_ACTIVATE_CMD: 703 status = mlo_link_set_active(psoc, req); 704 break; 705 case WLAN_SER_CB_CANCEL_CMD: 706 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: 707 mlo_err("vdev %d command not execute: %d", 708 wlan_vdev_get_id(vdev), reason); 709 if (req->ctx.set_mlo_link_cb) 710 req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, NULL); 711 break; 712 case WLAN_SER_CB_RELEASE_MEM_CMD: 713 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 714 qdf_mem_free(req); 715 break; 716 default: 717 QDF_ASSERT(0); 718 status = QDF_STATUS_E_INVAL; 719 break; 720 } 721 722 return status; 723 } 724 725 #define MLO_SER_CMD_TIMEOUT_MS 5000 726 QDF_STATUS mlo_ser_set_link_req(struct mlo_link_set_active_req *req) 727 { 728 struct wlan_serialization_command cmd = {0, }; 729 enum wlan_serialization_status ser_cmd_status; 730 QDF_STATUS status; 731 struct wlan_objmgr_vdev *vdev; 732 733 if (!req) 734 return QDF_STATUS_E_INVAL; 735 736 vdev = req->ctx.vdev; 737 status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLO_MGR_ID); 738 if (QDF_IS_STATUS_ERROR(status)) { 739 mlo_err("vdev %d unable to get reference", 740 wlan_vdev_get_id(vdev)); 741 return status; 742 } 743 744 cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK; 745 cmd.cmd_id = 0; 746 cmd.cmd_cb = mlo_ser_set_link_cb; 747 cmd.source = WLAN_UMAC_COMP_MLO_MGR; 748 cmd.is_high_priority = false; 749 cmd.cmd_timeout_duration = MLO_SER_CMD_TIMEOUT_MS; 750 cmd.vdev = vdev; 751 cmd.is_blocking = true; 752 cmd.umac_cmd = (void *)req; 753 754 ser_cmd_status = wlan_serialization_request(&cmd); 755 switch (ser_cmd_status) { 756 case WLAN_SER_CMD_PENDING: 757 /* command moved to pending list.Do nothing */ 758 break; 759 case WLAN_SER_CMD_ACTIVE: 760 /* command moved to active list. Do nothing */ 761 break; 762 default: 763 mlo_err("vdev %d ser cmd status %d", 764 wlan_vdev_get_id(vdev), ser_cmd_status); 765 status = QDF_STATUS_E_FAILURE; 766 } 767 768 if (QDF_IS_STATUS_SUCCESS(status)) 769 return status; 770 771 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 772 773 return status; 774 } 775 776 void mlo_mlme_handle_sta_csa_param(struct wlan_objmgr_vdev *vdev, 777 struct csa_offload_params *csa_param) 778 { 779 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 780 781 if (!mlo_ctx || !mlo_ctx->mlme_ops || 782 !mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param) 783 return; 784 785 mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param(vdev, csa_param); 786 } 787 788 QDF_STATUS 789 mlo_get_mlstats_vdev_params(struct wlan_objmgr_psoc *psoc, 790 struct mlo_stats_vdev_params *info, 791 uint8_t vdev_id) 792 { 793 struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; 794 struct wlan_objmgr_vdev *vdev; 795 int i; 796 uint16_t ml_vdev_cnt = 0; 797 798 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 799 WLAN_MLO_MGR_ID); 800 if (!vdev) { 801 mlo_err("vdev object is NULL for vdev %d", vdev_id); 802 return QDF_STATUS_E_INVAL; 803 } 804 805 mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list); 806 for (i = 0; i < ml_vdev_cnt; i++) { 807 info->ml_vdev_id[i] = wlan_vdev_get_id(ml_vdev_list[i]); 808 mlo_release_vdev_ref(ml_vdev_list[i]); 809 } 810 info->ml_vdev_count = ml_vdev_cnt; 811 mlo_release_vdev_ref(vdev); 812 813 return QDF_STATUS_SUCCESS; 814 } 815 816 static void ml_extract_link_state(struct wlan_objmgr_psoc *psoc, 817 struct ml_link_state_info_event *event) 818 { 819 QDF_STATUS status; 820 get_ml_link_state_cb resp_cb = NULL; 821 void *context = NULL; 822 uint8_t vdev_id; 823 824 vdev_id = event->vdev_id; 825 826 status = mlo_get_link_state_context(psoc, 827 &resp_cb, &context, vdev_id); 828 829 if (QDF_IS_STATUS_ERROR(status)) 830 return; 831 832 if (resp_cb) 833 resp_cb(event, context); 834 } 835 836 QDF_STATUS 837 wlan_handle_ml_link_state_info_event(struct wlan_objmgr_psoc *psoc, 838 struct ml_link_state_info_event *event) 839 { 840 if (!event) 841 return QDF_STATUS_E_NULL_VALUE; 842 843 ml_extract_link_state(psoc, event); 844 845 return QDF_STATUS_SUCCESS; 846 } 847 848 static QDF_STATUS ml_get_link_state_req_cb(struct scheduler_msg *msg) 849 { 850 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 851 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 852 struct mlo_link_state_cmd_params cmd = {0}; 853 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 854 struct wlan_objmgr_psoc *psoc; 855 int status = 0; 856 857 if (!vdev) { 858 mlo_err("null input vdev"); 859 return QDF_STATUS_E_INVAL; 860 } 861 862 psoc = wlan_vdev_get_psoc(vdev); 863 864 if (!psoc) { 865 mlo_err("null psoc"); 866 return QDF_STATUS_E_NULL_VALUE; 867 } 868 869 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 870 871 if (!mlo_tx_ops) { 872 mlo_err("tx_ops is null!"); 873 return QDF_STATUS_E_NULL_VALUE; 874 } 875 876 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 877 mlo_err("vdev is not MLO vdev"); 878 return status; 879 } 880 881 mlo_dev_ctx = vdev->mlo_dev_ctx; 882 cmd.vdev_id = vdev->vdev_objmgr.vdev_id; 883 qdf_mem_copy(&cmd.mld_mac[0], &mlo_dev_ctx->mld_addr, 884 QDF_MAC_ADDR_SIZE); 885 886 if (!mlo_tx_ops->request_link_state_info_cmd) { 887 mlo_err("handler is not registered"); 888 return QDF_STATUS_E_NULL_VALUE; 889 } 890 891 status = mlo_tx_ops->request_link_state_info_cmd(psoc, &cmd); 892 893 if (QDF_IS_STATUS_ERROR(status)) 894 mlo_err("failed to send ml link info command to FW"); 895 896 return QDF_STATUS_SUCCESS; 897 } 898 899 QDF_STATUS 900 mlo_get_link_state_register_resp_cb(struct wlan_objmgr_vdev *vdev, 901 struct ml_link_state_cmd_info *req) 902 { 903 struct wlan_mlo_dev_context *mlo_ctx; 904 struct wlan_mlo_sta *sta_ctx = NULL; 905 906 if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 907 return QDF_STATUS_E_NULL_VALUE; 908 mlo_ctx = vdev->mlo_dev_ctx; 909 910 if (!mlo_ctx) { 911 mlo_err("null mlo_dev_ctx"); 912 return QDF_STATUS_E_NULL_VALUE; 913 } 914 915 sta_ctx = mlo_ctx->sta_ctx; 916 917 if (!sta_ctx) 918 return QDF_STATUS_E_INVAL; 919 920 mlo_dev_lock_acquire(mlo_ctx); 921 922 sta_ctx->ml_link_state.ml_link_state_resp_cb = 923 req->ml_link_state_resp_cb; 924 sta_ctx->ml_link_state.ml_link_state_req_context = 925 req->request_cookie; 926 mlo_dev_lock_release(mlo_ctx); 927 928 return QDF_STATUS_SUCCESS; 929 } 930 931 static QDF_STATUS ml_get_link_state_req_flush_cb(struct scheduler_msg *msg) 932 { 933 mlo_debug("ml_get_link_state_req flush callback"); 934 return QDF_STATUS_SUCCESS; 935 } 936 937 QDF_STATUS ml_post_get_link_state_msg(struct wlan_objmgr_vdev *vdev) 938 { 939 struct scheduler_msg msg = {0}; 940 QDF_STATUS qdf_status = 0; 941 942 msg.bodyptr = vdev; 943 msg.callback = ml_get_link_state_req_cb; 944 msg.flush_callback = ml_get_link_state_req_flush_cb; 945 946 qdf_status = scheduler_post_message( 947 QDF_MODULE_ID_OS_IF, 948 QDF_MODULE_ID_MLME, 949 QDF_MODULE_ID_OS_IF, 950 &msg); 951 return qdf_status; 952 } 953 954