1 /* 2 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <wlan_utility.h> 17 #include <dp_internal.h> 18 #include <dp_htt.h> 19 #include <hal_be_api.h> 20 #include "dp_mlo.h" 21 #include <dp_be.h> 22 #include <dp_htt.h> 23 #include <dp_internal.h> 24 #include <wlan_cfg.h> 25 #include <wlan_mlo_mgr_cmn.h> 26 /* 27 * dp_mlo_ctxt_attach_wifi3 () – Attach DP MLO context 28 * 29 * Return: DP MLO context handle on success, NULL on failure 30 */ 31 struct cdp_mlo_ctxt * 32 dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt) 33 { 34 struct dp_mlo_ctxt *mlo_ctxt = 35 qdf_mem_malloc(sizeof(struct dp_mlo_ctxt)); 36 37 if (!mlo_ctxt) { 38 dp_err("Failed to allocate DP MLO Context"); 39 return NULL; 40 } 41 42 mlo_ctxt->ctrl_ctxt = ctrl_ctxt; 43 44 if (dp_mlo_peer_find_hash_attach_be 45 (mlo_ctxt, DP_MAX_MLO_PEER) != QDF_STATUS_SUCCESS) { 46 dp_err("Failed to allocate peer hash"); 47 qdf_mem_free(mlo_ctxt); 48 return NULL; 49 } 50 51 qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock); 52 return dp_mlo_ctx_to_cdp(mlo_ctxt); 53 } 54 55 qdf_export_symbol(dp_mlo_ctxt_attach_wifi3); 56 57 /* 58 * dp_mlo_ctxt_detach_wifi3 () – Detach DP MLO context 59 * 60 * @ml_ctxt: pointer to DP MLO context 61 * 62 * Return: void 63 */ 64 void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt) 65 { 66 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 67 68 if (!cdp_ml_ctxt) 69 return; 70 71 qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock); 72 dp_mlo_peer_find_hash_detach_be(mlo_ctxt); 73 qdf_mem_free(mlo_ctxt); 74 } 75 76 qdf_export_symbol(dp_mlo_ctxt_detach_wifi3); 77 78 /* 79 * dp_mlo_set_soc_by_chip_id() – Add DP soc to ML context soc list 80 * 81 * @ml_ctxt: DP ML context handle 82 * @soc: DP soc handle 83 * @chip_id: MLO chip id 84 * 85 * Return: void 86 */ 87 void dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt *ml_ctxt, 88 struct dp_soc *soc, 89 uint8_t chip_id) 90 { 91 qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock); 92 ml_ctxt->ml_soc_list[chip_id] = soc; 93 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); 94 } 95 96 /* 97 * dp_mlo_get_soc_ref_by_chip_id() – Get DP soc from DP ML context. 98 * This API will increment a reference count for DP soc. Caller has 99 * to take care for decrementing refcount. 100 * 101 * @ml_ctxt: DP ML context handle 102 * @chip_id: MLO chip id 103 * 104 * Return: dp_soc 105 */ 106 struct dp_soc* 107 dp_mlo_get_soc_ref_by_chip_id(struct dp_mlo_ctxt *ml_ctxt, 108 uint8_t chip_id) 109 { 110 struct dp_soc *soc = NULL; 111 112 if (!ml_ctxt) { 113 dp_warn("MLO context not created, MLO not enabled"); 114 return NULL; 115 } 116 117 qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock); 118 soc = ml_ctxt->ml_soc_list[chip_id]; 119 120 if (!soc) { 121 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); 122 return NULL; 123 } 124 125 qdf_atomic_inc(&soc->ref_count); 126 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); 127 128 return soc; 129 } 130 131 static QDF_STATUS dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt *mlo_ctxt, 132 struct dp_soc_be *be_soc) 133 { 134 uint8_t i; 135 struct dp_soc *partner_soc; 136 struct dp_soc_be *be_partner_soc; 137 uint8_t pool_id; 138 QDF_STATUS qdf_status; 139 140 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) { 141 partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i); 142 if (!partner_soc) 143 continue; 144 145 be_partner_soc = dp_get_be_soc_from_dp_soc(partner_soc); 146 147 for (pool_id = 0; pool_id < MAX_RXDESC_POOLS; pool_id++) { 148 qdf_status = 149 dp_hw_cookie_conversion_init 150 (be_soc, 151 &be_partner_soc->rx_cc_ctx[pool_id]); 152 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 153 dp_alert("MLO partner soc RX CC init failed"); 154 return qdf_status; 155 } 156 } 157 } 158 159 return qdf_status; 160 } 161 162 static void dp_mlo_soc_setup(struct cdp_soc_t *soc_hdl, 163 struct cdp_mlo_ctxt *cdp_ml_ctxt) 164 { 165 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 166 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 167 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 168 169 if (!cdp_ml_ctxt) 170 return; 171 172 dp_mlo_set_soc_by_chip_id(mlo_ctxt, soc, be_soc->mlo_chip_id); 173 } 174 175 static void dp_mlo_soc_teardown(struct cdp_soc_t *soc_hdl, 176 struct cdp_mlo_ctxt *cdp_ml_ctxt) 177 { 178 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 179 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 180 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 181 182 if (!cdp_ml_ctxt) 183 return; 184 185 dp_mlo_set_soc_by_chip_id(mlo_ctxt, NULL, be_soc->mlo_chip_id); 186 } 187 188 static QDF_STATUS dp_mlo_add_ptnr_vdev(struct dp_vdev *vdev1, 189 struct dp_vdev *vdev2, 190 struct dp_soc *soc, uint8_t pdev_id) 191 { 192 struct dp_soc_be *soc_be = dp_get_be_soc_from_dp_soc(soc); 193 struct dp_vdev_be *vdev2_be = dp_get_be_vdev_from_dp_vdev(vdev2); 194 195 /* return when valid entry exists */ 196 if (vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] != 197 CDP_INVALID_VDEV_ID) 198 return QDF_STATUS_SUCCESS; 199 200 if (dp_vdev_get_ref(soc, vdev1, DP_MOD_ID_RX) != 201 QDF_STATUS_SUCCESS) { 202 qdf_info("%pK: unable to get vdev reference vdev %pK vdev_id %u", 203 soc, vdev1, vdev1->vdev_id); 204 return QDF_STATUS_E_FAILURE; 205 } 206 207 vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] = 208 vdev1->vdev_id; 209 210 mlo_debug("Add vdev%d to vdev%d list, mlo_chip_id = %d pdev_id = %d\n", 211 vdev1->vdev_id, vdev2->vdev_id, soc_be->mlo_chip_id, pdev_id); 212 213 return QDF_STATUS_SUCCESS; 214 } 215 216 QDF_STATUS dp_update_mlo_ptnr_list(struct cdp_soc_t *soc_hdl, 217 int8_t partner_vdev_ids[], uint8_t num_vdevs, 218 uint8_t self_vdev_id) 219 { 220 int i, j; 221 struct dp_soc *self_soc = cdp_soc_t_to_dp_soc(soc_hdl); 222 struct dp_vdev *self_vdev; 223 QDF_STATUS ret = QDF_STATUS_SUCCESS; 224 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(self_soc); 225 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 226 227 if (!dp_mlo) 228 return QDF_STATUS_E_FAILURE; 229 230 self_vdev = dp_vdev_get_ref_by_id(self_soc, self_vdev_id, DP_MOD_ID_RX); 231 if (!self_vdev) 232 return QDF_STATUS_E_FAILURE; 233 234 /* go through the input vdev id list and if there are partner vdevs, 235 * - then add the current vdev's id to partner vdev's list using pdev_id and 236 * increase the reference 237 * - add partner vdev to self list and increase the reference 238 */ 239 for (i = 0; i < num_vdevs; i++) { 240 if (partner_vdev_ids[i] == CDP_INVALID_VDEV_ID) 241 continue; 242 243 for (j = 0; j < WLAN_MAX_MLO_CHIPS; j++) { 244 struct dp_soc *soc = 245 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, j); 246 if (soc) { 247 struct dp_vdev *vdev; 248 249 vdev = dp_vdev_get_ref_by_id(soc, 250 partner_vdev_ids[i], DP_MOD_ID_RX); 251 if (vdev) { 252 if (vdev == self_vdev) { 253 dp_vdev_unref_delete(soc, 254 vdev, DP_MOD_ID_RX); 255 /*dp_soc_unref_delete(soc); */ 256 continue; 257 } 258 if (qdf_is_macaddr_equal( 259 (struct qdf_mac_addr *)self_vdev->mld_mac_addr.raw, 260 (struct qdf_mac_addr *)vdev->mld_mac_addr.raw)) { 261 if (dp_mlo_add_ptnr_vdev(self_vdev, 262 vdev, self_soc, 263 self_vdev->pdev->pdev_id) != 264 QDF_STATUS_SUCCESS) { 265 dp_err("Unable to add self to partner vdev's list"); 266 dp_vdev_unref_delete(soc, 267 vdev, DP_MOD_ID_RX); 268 /* TODO - release soc ref here */ 269 /* dp_soc_unref_delete(soc);*/ 270 ret = QDF_STATUS_E_FAILURE; 271 goto exit; 272 } 273 /* add to self list */ 274 if (dp_mlo_add_ptnr_vdev(vdev, self_vdev, soc, 275 vdev->pdev->pdev_id) != 276 QDF_STATUS_SUCCESS) { 277 dp_err("Unable to add vdev to self vdev's list"); 278 dp_vdev_unref_delete(self_soc, 279 vdev, DP_MOD_ID_RX); 280 /* TODO - relase soc ref here */ 281 /* dp_soc_unref_delete(soc);*/ 282 ret = QDF_STATUS_E_FAILURE; 283 goto exit; 284 } 285 } 286 dp_vdev_unref_delete(soc, vdev, 287 DP_MOD_ID_RX); 288 } /* vdev */ 289 /* TODO - release soc ref here */ 290 /* dp_soc_unref_delete(soc); */ 291 } /* soc */ 292 } /* for */ 293 } /* for */ 294 295 exit: 296 dp_vdev_unref_delete(self_soc, self_vdev, DP_MOD_ID_RX); 297 return ret; 298 } 299 300 void dp_clr_mlo_ptnr_list(struct dp_soc *soc, struct dp_vdev *vdev) 301 { 302 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 303 struct dp_vdev_be *vdev_be = dp_get_be_vdev_from_dp_vdev(vdev); 304 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 305 uint8_t soc_id = be_soc->mlo_chip_id; 306 uint8_t pdev_id = vdev->pdev->pdev_id; 307 int i, j; 308 309 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) { 310 for (j = 0; j < WLAN_MAX_MLO_LINKS_PER_SOC; j++) { 311 struct dp_vdev *pr_vdev; 312 struct dp_soc *pr_soc; 313 struct dp_soc_be *pr_soc_be; 314 struct dp_pdev *pr_pdev; 315 struct dp_vdev_be *pr_vdev_be; 316 317 if (vdev_be->partner_vdev_list[i][j] == 318 CDP_INVALID_VDEV_ID) 319 continue; 320 321 pr_soc = dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 322 pr_soc_be = dp_get_be_soc_from_dp_soc(pr_soc); 323 pr_vdev = dp_vdev_get_ref_by_id(pr_soc, 324 vdev_be->partner_vdev_list[i][j], 325 DP_MOD_ID_RX); 326 if (!pr_vdev) 327 continue; 328 329 /* release ref and remove self vdev from partner list */ 330 pr_vdev_be = dp_get_be_vdev_from_dp_vdev(pr_vdev); 331 dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX); 332 pr_vdev_be->partner_vdev_list[soc_id][pdev_id] = 333 CDP_INVALID_VDEV_ID; 334 335 /* release ref and remove partner vdev from self list */ 336 dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX); 337 pr_pdev = pr_vdev->pdev; 338 vdev_be->partner_vdev_list[pr_soc_be->mlo_chip_id][pr_pdev->pdev_id] = 339 CDP_INVALID_VDEV_ID; 340 341 dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX); 342 } 343 } 344 } 345 346 static void dp_mlo_setup_complete(struct cdp_mlo_ctxt *cdp_ml_ctxt) 347 { 348 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 349 int i; 350 struct dp_soc *soc; 351 struct dp_soc_be *be_soc; 352 QDF_STATUS qdf_status; 353 354 if (!cdp_ml_ctxt) 355 return; 356 357 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) { 358 soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i); 359 360 if (!soc) 361 continue; 362 be_soc = dp_get_be_soc_from_dp_soc(soc); 363 364 qdf_status = dp_partner_soc_rx_hw_cc_init(mlo_ctxt, be_soc); 365 366 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 367 dp_alert("MLO partner SOC Rx desc CC init failed"); 368 qdf_assert_always(0); 369 } 370 } 371 } 372 373 static struct cdp_mlo_ops dp_mlo_ops = { 374 .mlo_soc_setup = dp_mlo_soc_setup, 375 .mlo_soc_teardown = dp_mlo_soc_teardown, 376 .update_mlo_ptnr_list = dp_update_mlo_ptnr_list, 377 .mlo_setup_complete = dp_mlo_setup_complete, 378 }; 379 380 void dp_soc_mlo_fill_params(struct dp_soc *soc, 381 struct cdp_soc_attach_params *params) 382 { 383 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 384 385 if (!params->mlo_enabled) { 386 dp_warn("MLO not enabled on SOC"); 387 return; 388 } 389 390 be_soc->mlo_chip_id = params->mlo_chip_id; 391 be_soc->ml_ctxt = cdp_mlo_ctx_to_dp(params->ml_context); 392 be_soc->mlo_enabled = 1; 393 soc->cdp_soc.ops->mlo_ops = &dp_mlo_ops; 394 } 395 396 void dp_pdev_mlo_fill_params(struct dp_pdev *pdev, 397 struct cdp_pdev_attach_params *params) 398 { 399 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(pdev->soc); 400 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev); 401 402 if (!be_soc->mlo_enabled) { 403 dp_info("MLO not enabled on SOC"); 404 return; 405 } 406 407 be_pdev->mlo_link_id = params->mlo_link_id; 408 } 409 410 void dp_mlo_partner_chips_map(struct dp_soc *soc, 411 struct dp_peer *peer, 412 uint16_t peer_id) 413 { 414 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 415 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 416 bool is_ml_peer_id = 417 HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id); 418 uint8_t chip_id; 419 struct dp_soc *temp_soc; 420 421 if (!mlo_ctxt) 422 return; 423 424 /* for non ML peer dont map on partner chips*/ 425 if (!is_ml_peer_id) 426 return; 427 428 qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock); 429 for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) { 430 temp_soc = mlo_ctxt->ml_soc_list[chip_id]; 431 432 if (!temp_soc) 433 continue; 434 435 /* skip if this is current soc */ 436 if (temp_soc == soc) 437 continue; 438 439 dp_peer_find_id_to_obj_add(temp_soc, peer, peer_id); 440 } 441 qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock); 442 } 443 444 qdf_export_symbol(dp_mlo_partner_chips_map); 445 446 void dp_mlo_partner_chips_unmap(struct dp_soc *soc, 447 uint16_t peer_id) 448 { 449 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 450 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 451 bool is_ml_peer_id = 452 HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id); 453 uint8_t chip_id; 454 struct dp_soc *temp_soc; 455 456 if (!is_ml_peer_id) 457 return; 458 459 if (!mlo_ctxt) 460 return; 461 462 qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock); 463 for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) { 464 temp_soc = mlo_ctxt->ml_soc_list[chip_id]; 465 466 if (!temp_soc) 467 continue; 468 469 /* skip if this is current soc */ 470 if (temp_soc == soc) 471 continue; 472 473 dp_peer_find_id_to_obj_remove(temp_soc, peer_id); 474 } 475 qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock); 476 } 477 478 qdf_export_symbol(dp_mlo_partner_chips_unmap); 479 480 uint8_t dp_mlo_get_chip_id(struct dp_soc *soc) 481 { 482 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 483 484 return be_soc->mlo_chip_id; 485 } 486 487 qdf_export_symbol(dp_mlo_get_chip_id); 488 489 struct dp_peer * 490 dp_link_peer_hash_find_by_chip_id(struct dp_soc *soc, 491 uint8_t *peer_mac_addr, 492 int mac_addr_is_aligned, 493 uint8_t vdev_id, 494 uint8_t chip_id, 495 enum dp_mod_id mod_id) 496 { 497 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 498 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 499 struct dp_soc *link_peer_soc = NULL; 500 struct dp_peer *peer = NULL; 501 502 if (!mlo_ctxt) 503 return NULL; 504 505 link_peer_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id); 506 507 if (!link_peer_soc) 508 return NULL; 509 510 peer = dp_peer_find_hash_find(link_peer_soc, peer_mac_addr, 511 mac_addr_is_aligned, vdev_id, 512 mod_id); 513 qdf_atomic_dec(&link_peer_soc->ref_count); 514 return peer; 515 } 516 517 qdf_export_symbol(dp_link_peer_hash_find_by_chip_id); 518 519 struct dp_soc * 520 dp_rx_replensih_soc_get(struct dp_soc *soc, uint8_t reo_ring_num) 521 { 522 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 523 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 524 uint8_t chip_id; 525 uint8_t rx_ring_mask; 526 527 if (!be_soc->mlo_enabled || !mlo_ctxt) 528 return soc; 529 530 for (chip_id = 0; chip_id < WLAN_MAX_MLO_CHIPS; chip_id++) { 531 rx_ring_mask = 532 wlan_cfg_mlo_rx_ring_map_get_by_chip_id 533 (soc->wlan_cfg_ctx, chip_id); 534 535 if (rx_ring_mask & (1 << reo_ring_num)) 536 return dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id); 537 } 538 539 return soc; 540 } 541 542 #ifdef WLAN_MCAST_MLO 543 void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc, 544 struct dp_vdev_be *be_vdev, 545 dp_ptnr_vdev_iter_func func, 546 void *arg, 547 enum dp_mod_id mod_id) 548 { 549 int i = 0; 550 int j = 0; 551 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 552 553 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { 554 struct dp_soc *ptnr_soc = 555 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 556 557 if (!ptnr_soc) 558 continue; 559 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) { 560 struct dp_vdev *ptnr_vdev; 561 562 ptnr_vdev = dp_vdev_get_ref_by_id( 563 ptnr_soc, 564 be_vdev->partner_vdev_list[i][j], 565 mod_id); 566 if (!ptnr_vdev) 567 continue; 568 (*func)(be_vdev, ptnr_vdev, arg); 569 dp_vdev_unref_delete(ptnr_vdev->pdev->soc, 570 ptnr_vdev, 571 mod_id); 572 } 573 } 574 } 575 576 qdf_export_symbol(dp_mcast_mlo_iter_ptnr_vdev); 577 578 struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc, 579 struct dp_vdev_be *be_vdev, 580 enum dp_mod_id mod_id) 581 { 582 int i = 0; 583 int j = 0; 584 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 585 586 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { 587 struct dp_soc *ptnr_soc = 588 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 589 590 if (!ptnr_soc) 591 continue; 592 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) { 593 struct dp_vdev *ptnr_vdev = NULL; 594 struct dp_vdev_be *be_ptnr_vdev = NULL; 595 596 ptnr_vdev = dp_vdev_get_ref_by_id( 597 ptnr_soc, 598 be_vdev->partner_vdev_list[i][j], 599 mod_id); 600 if (!ptnr_vdev) 601 continue; 602 be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev); 603 if (be_ptnr_vdev->mcast_primary) 604 return ptnr_vdev; 605 dp_vdev_unref_delete(be_ptnr_vdev->vdev.pdev->soc, 606 &be_ptnr_vdev->vdev, 607 mod_id); 608 } 609 } 610 return NULL; 611 } 612 613 qdf_export_symbol(dp_mlo_get_mcast_primary_vdev); 614 #endif 615