1 /* 2 * Copyright (c) 2021-2023 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_be_rx.h> 23 #include <dp_htt.h> 24 #include <dp_internal.h> 25 #include <wlan_cfg.h> 26 #include <wlan_mlo_mgr_cmn.h> 27 28 /** 29 * dp_mlo_ctxt_attach_wifi3() - Attach DP MLO context 30 * @ctrl_ctxt: CDP control context 31 * 32 * Return: DP MLO context handle on success, NULL on failure 33 */ 34 static struct cdp_mlo_ctxt * 35 dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt) 36 { 37 struct dp_mlo_ctxt *mlo_ctxt = 38 qdf_mem_malloc(sizeof(struct dp_mlo_ctxt)); 39 40 if (!mlo_ctxt) { 41 dp_err("Failed to allocate DP MLO Context"); 42 return NULL; 43 } 44 45 mlo_ctxt->ctrl_ctxt = ctrl_ctxt; 46 47 if (dp_mlo_peer_find_hash_attach_be 48 (mlo_ctxt, DP_MAX_MLO_PEER) != QDF_STATUS_SUCCESS) { 49 dp_err("Failed to allocate peer hash"); 50 qdf_mem_free(mlo_ctxt); 51 return NULL; 52 } 53 54 qdf_get_random_bytes(mlo_ctxt->toeplitz_hash_ipv4, 55 (sizeof(mlo_ctxt->toeplitz_hash_ipv4[0]) * 56 LRO_IPV4_SEED_ARR_SZ)); 57 qdf_get_random_bytes(mlo_ctxt->toeplitz_hash_ipv6, 58 (sizeof(mlo_ctxt->toeplitz_hash_ipv6[0]) * 59 LRO_IPV6_SEED_ARR_SZ)); 60 61 qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock); 62 return dp_mlo_ctx_to_cdp(mlo_ctxt); 63 } 64 65 /** 66 * dp_mlo_ctxt_detach_wifi3() - Detach DP MLO context 67 * @cdp_ml_ctxt: pointer to CDP DP MLO context 68 * 69 * Return: void 70 */ 71 static void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt) 72 { 73 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 74 75 if (!cdp_ml_ctxt) 76 return; 77 78 qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock); 79 dp_mlo_peer_find_hash_detach_be(mlo_ctxt); 80 qdf_mem_free(mlo_ctxt); 81 } 82 83 /* 84 * dp_mlo_set_soc_by_chip_id() – Add DP soc to ML context soc list 85 * 86 * @ml_ctxt: DP ML context handle 87 * @soc: DP soc handle 88 * @chip_id: MLO chip id 89 * 90 * Return: void 91 */ 92 void dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt *ml_ctxt, 93 struct dp_soc *soc, 94 uint8_t chip_id) 95 { 96 qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock); 97 ml_ctxt->ml_soc_list[chip_id] = soc; 98 99 /* The same API is called during soc_attach and soc_detach 100 * soc parameter is non-null or null accordingly. 101 */ 102 if (soc) 103 ml_ctxt->ml_soc_cnt++; 104 else 105 ml_ctxt->ml_soc_cnt--; 106 107 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); 108 } 109 110 /* 111 * dp_mlo_get_soc_ref_by_chip_id() – Get DP soc from DP ML context. 112 * This API will increment a reference count for DP soc. Caller has 113 * to take care for decrementing refcount. 114 * 115 * @ml_ctxt: DP ML context handle 116 * @chip_id: MLO chip id 117 * 118 * Return: dp_soc 119 */ 120 struct dp_soc* 121 dp_mlo_get_soc_ref_by_chip_id(struct dp_mlo_ctxt *ml_ctxt, 122 uint8_t chip_id) 123 { 124 struct dp_soc *soc = NULL; 125 126 if (!ml_ctxt) { 127 dp_warn("MLO context not created, MLO not enabled"); 128 return NULL; 129 } 130 131 qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock); 132 soc = ml_ctxt->ml_soc_list[chip_id]; 133 134 if (!soc) { 135 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); 136 return NULL; 137 } 138 139 qdf_atomic_inc(&soc->ref_count); 140 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); 141 142 return soc; 143 } 144 145 static QDF_STATUS dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt *mlo_ctxt, 146 struct dp_soc_be *be_soc) 147 { 148 uint8_t i; 149 struct dp_soc *partner_soc; 150 struct dp_soc_be *be_partner_soc; 151 uint8_t pool_id; 152 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; 153 154 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) { 155 partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i); 156 if (!partner_soc) { 157 dp_err("partner_soc is NULL"); 158 continue; 159 } 160 161 be_partner_soc = dp_get_be_soc_from_dp_soc(partner_soc); 162 163 for (pool_id = 0; pool_id < MAX_RXDESC_POOLS; pool_id++) { 164 qdf_status = 165 dp_hw_cookie_conversion_init 166 (be_soc, 167 &be_partner_soc->rx_cc_ctx[pool_id]); 168 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 169 dp_alert("MLO partner soc RX CC init failed"); 170 return qdf_status; 171 } 172 } 173 } 174 175 return qdf_status; 176 } 177 178 static void dp_mlo_soc_drain_rx_buf(struct dp_soc *soc, void *arg) 179 { 180 uint8_t i = 0; 181 uint8_t cpu = 0; 182 uint8_t rx_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0}; 183 uint8_t rx_err_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0}; 184 uint8_t rx_wbm_rel_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0}; 185 uint8_t reo_status_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0}; 186 187 /* Save the current interrupt mask and disable the interrupts */ 188 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) { 189 rx_ring_mask[i] = soc->intr_ctx[i].rx_ring_mask; 190 rx_err_ring_mask[i] = soc->intr_ctx[i].rx_err_ring_mask; 191 rx_wbm_rel_ring_mask[i] = soc->intr_ctx[i].rx_wbm_rel_ring_mask; 192 reo_status_ring_mask[i] = soc->intr_ctx[i].reo_status_ring_mask; 193 194 soc->intr_ctx[i].rx_ring_mask = 0; 195 soc->intr_ctx[i].rx_err_ring_mask = 0; 196 soc->intr_ctx[i].rx_wbm_rel_ring_mask = 0; 197 soc->intr_ctx[i].reo_status_ring_mask = 0; 198 } 199 200 /* make sure dp_service_srngs not running on any of the CPU */ 201 for (cpu = 0; cpu < NR_CPUS; cpu++) { 202 while (qdf_atomic_test_bit(cpu, 203 &soc->service_rings_running)) 204 ; 205 } 206 207 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) { 208 uint8_t ring = 0; 209 uint32_t num_entries = 0; 210 hal_ring_handle_t hal_ring_hdl = NULL; 211 uint8_t rx_mask = wlan_cfg_get_rx_ring_mask( 212 soc->wlan_cfg_ctx, i); 213 uint8_t rx_err_mask = wlan_cfg_get_rx_err_ring_mask( 214 soc->wlan_cfg_ctx, i); 215 uint8_t rx_wbm_rel_mask = wlan_cfg_get_rx_wbm_rel_ring_mask( 216 soc->wlan_cfg_ctx, i); 217 218 if (rx_mask) { 219 /* iterate through each reo ring and process the buf */ 220 for (ring = 0; ring < soc->num_reo_dest_rings; ring++) { 221 if (!(rx_mask & (1 << ring))) 222 continue; 223 224 hal_ring_hdl = 225 soc->reo_dest_ring[ring].hal_srng; 226 num_entries = hal_srng_get_num_entries( 227 soc->hal_soc, 228 hal_ring_hdl); 229 dp_rx_process_be(&soc->intr_ctx[i], 230 hal_ring_hdl, 231 ring, 232 num_entries); 233 } 234 } 235 236 /* Process REO Exception ring */ 237 if (rx_err_mask) { 238 hal_ring_hdl = soc->reo_exception_ring.hal_srng; 239 num_entries = hal_srng_get_num_entries( 240 soc->hal_soc, 241 hal_ring_hdl); 242 243 dp_rx_err_process(&soc->intr_ctx[i], soc, 244 hal_ring_hdl, num_entries); 245 } 246 247 /* Process Rx WBM release ring */ 248 if (rx_wbm_rel_mask) { 249 hal_ring_hdl = soc->rx_rel_ring.hal_srng; 250 num_entries = hal_srng_get_num_entries( 251 soc->hal_soc, 252 hal_ring_hdl); 253 254 dp_rx_wbm_err_process(&soc->intr_ctx[i], soc, 255 hal_ring_hdl, num_entries); 256 } 257 } 258 259 /* restore the interrupt mask */ 260 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) { 261 soc->intr_ctx[i].rx_ring_mask = rx_ring_mask[i]; 262 soc->intr_ctx[i].rx_err_ring_mask = rx_err_ring_mask[i]; 263 soc->intr_ctx[i].rx_wbm_rel_ring_mask = rx_wbm_rel_ring_mask[i]; 264 soc->intr_ctx[i].reo_status_ring_mask = reo_status_ring_mask[i]; 265 } 266 } 267 268 static void dp_mlo_soc_setup(struct cdp_soc_t *soc_hdl, 269 struct cdp_mlo_ctxt *cdp_ml_ctxt) 270 { 271 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 272 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 273 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 274 uint8_t pdev_id; 275 276 if (!cdp_ml_ctxt) 277 return; 278 279 be_soc->ml_ctxt = mlo_ctxt; 280 281 for (pdev_id = 0; pdev_id < MAX_PDEV_CNT; pdev_id++) { 282 if (soc->pdev_list[pdev_id]) 283 dp_mlo_update_link_to_pdev_map(soc, 284 soc->pdev_list[pdev_id]); 285 } 286 287 dp_mlo_set_soc_by_chip_id(mlo_ctxt, soc, be_soc->mlo_chip_id); 288 } 289 290 static void dp_mlo_soc_teardown(struct cdp_soc_t *soc_hdl, 291 struct cdp_mlo_ctxt *cdp_ml_ctxt, 292 bool is_force_down) 293 { 294 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 295 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 296 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 297 298 if (!cdp_ml_ctxt) 299 return; 300 301 /* During the teardown drain the Rx buffers if any exist in the ring */ 302 dp_mcast_mlo_iter_ptnr_soc(be_soc, 303 dp_mlo_soc_drain_rx_buf, 304 NULL); 305 306 dp_mlo_set_soc_by_chip_id(mlo_ctxt, NULL, be_soc->mlo_chip_id); 307 be_soc->ml_ctxt = NULL; 308 } 309 310 static QDF_STATUS dp_mlo_add_ptnr_vdev(struct dp_vdev *vdev1, 311 struct dp_vdev *vdev2, 312 struct dp_soc *soc, uint8_t pdev_id) 313 { 314 struct dp_soc_be *soc_be = dp_get_be_soc_from_dp_soc(soc); 315 struct dp_vdev_be *vdev2_be = dp_get_be_vdev_from_dp_vdev(vdev2); 316 317 /* return when valid entry exists */ 318 if (vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] != 319 CDP_INVALID_VDEV_ID) 320 return QDF_STATUS_SUCCESS; 321 322 if (dp_vdev_get_ref(soc, vdev1, DP_MOD_ID_RX) != 323 QDF_STATUS_SUCCESS) { 324 qdf_info("%pK: unable to get vdev reference vdev %pK vdev_id %u", 325 soc, vdev1, vdev1->vdev_id); 326 return QDF_STATUS_E_FAILURE; 327 } 328 329 vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] = 330 vdev1->vdev_id; 331 332 mlo_debug("Add vdev%d to vdev%d list, mlo_chip_id = %d pdev_id = %d\n", 333 vdev1->vdev_id, vdev2->vdev_id, soc_be->mlo_chip_id, pdev_id); 334 335 return QDF_STATUS_SUCCESS; 336 } 337 338 QDF_STATUS dp_update_mlo_ptnr_list(struct cdp_soc_t *soc_hdl, 339 int8_t partner_vdev_ids[], uint8_t num_vdevs, 340 uint8_t self_vdev_id) 341 { 342 int i, j; 343 struct dp_soc *self_soc = cdp_soc_t_to_dp_soc(soc_hdl); 344 struct dp_vdev *self_vdev; 345 QDF_STATUS ret = QDF_STATUS_SUCCESS; 346 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(self_soc); 347 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 348 349 if (!dp_mlo) 350 return QDF_STATUS_E_FAILURE; 351 352 self_vdev = dp_vdev_get_ref_by_id(self_soc, self_vdev_id, DP_MOD_ID_RX); 353 if (!self_vdev) 354 return QDF_STATUS_E_FAILURE; 355 356 /* go through the input vdev id list and if there are partner vdevs, 357 * - then add the current vdev's id to partner vdev's list using pdev_id and 358 * increase the reference 359 * - add partner vdev to self list and increase the reference 360 */ 361 for (i = 0; i < num_vdevs; i++) { 362 if (partner_vdev_ids[i] == CDP_INVALID_VDEV_ID) 363 continue; 364 365 for (j = 0; j < WLAN_MAX_MLO_CHIPS; j++) { 366 struct dp_soc *soc = 367 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, j); 368 if (soc) { 369 struct dp_vdev *vdev; 370 371 vdev = dp_vdev_get_ref_by_id(soc, 372 partner_vdev_ids[i], DP_MOD_ID_RX); 373 if (vdev) { 374 if (vdev == self_vdev) { 375 dp_vdev_unref_delete(soc, 376 vdev, DP_MOD_ID_RX); 377 /*dp_soc_unref_delete(soc); */ 378 continue; 379 } 380 if (qdf_is_macaddr_equal( 381 (struct qdf_mac_addr *)self_vdev->mld_mac_addr.raw, 382 (struct qdf_mac_addr *)vdev->mld_mac_addr.raw)) { 383 if (dp_mlo_add_ptnr_vdev(self_vdev, 384 vdev, self_soc, 385 self_vdev->pdev->pdev_id) != 386 QDF_STATUS_SUCCESS) { 387 dp_err("Unable to add self to partner vdev's list"); 388 dp_vdev_unref_delete(soc, 389 vdev, DP_MOD_ID_RX); 390 /* TODO - release soc ref here */ 391 /* dp_soc_unref_delete(soc);*/ 392 ret = QDF_STATUS_E_FAILURE; 393 goto exit; 394 } 395 /* add to self list */ 396 if (dp_mlo_add_ptnr_vdev(vdev, self_vdev, soc, 397 vdev->pdev->pdev_id) != 398 QDF_STATUS_SUCCESS) { 399 dp_err("Unable to add vdev to self vdev's list"); 400 dp_vdev_unref_delete(self_soc, 401 vdev, DP_MOD_ID_RX); 402 /* TODO - release soc ref here */ 403 /* dp_soc_unref_delete(soc);*/ 404 ret = QDF_STATUS_E_FAILURE; 405 goto exit; 406 } 407 } 408 dp_vdev_unref_delete(soc, vdev, 409 DP_MOD_ID_RX); 410 } /* vdev */ 411 /* TODO - release soc ref here */ 412 /* dp_soc_unref_delete(soc); */ 413 } /* soc */ 414 } /* for */ 415 } /* for */ 416 417 exit: 418 dp_vdev_unref_delete(self_soc, self_vdev, DP_MOD_ID_RX); 419 return ret; 420 } 421 422 void dp_clr_mlo_ptnr_list(struct dp_soc *soc, struct dp_vdev *vdev) 423 { 424 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 425 struct dp_vdev_be *vdev_be = dp_get_be_vdev_from_dp_vdev(vdev); 426 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 427 uint8_t soc_id = be_soc->mlo_chip_id; 428 uint8_t pdev_id = vdev->pdev->pdev_id; 429 int i, j; 430 431 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) { 432 for (j = 0; j < WLAN_MAX_MLO_LINKS_PER_SOC; j++) { 433 struct dp_vdev *pr_vdev; 434 struct dp_soc *pr_soc; 435 struct dp_soc_be *pr_soc_be; 436 struct dp_pdev *pr_pdev; 437 struct dp_vdev_be *pr_vdev_be; 438 439 if (vdev_be->partner_vdev_list[i][j] == 440 CDP_INVALID_VDEV_ID) 441 continue; 442 443 pr_soc = dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 444 if (!pr_soc) 445 continue; 446 pr_soc_be = dp_get_be_soc_from_dp_soc(pr_soc); 447 pr_vdev = dp_vdev_get_ref_by_id(pr_soc, 448 vdev_be->partner_vdev_list[i][j], 449 DP_MOD_ID_RX); 450 if (!pr_vdev) 451 continue; 452 453 /* release ref and remove self vdev from partner list */ 454 pr_vdev_be = dp_get_be_vdev_from_dp_vdev(pr_vdev); 455 dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX); 456 pr_vdev_be->partner_vdev_list[soc_id][pdev_id] = 457 CDP_INVALID_VDEV_ID; 458 459 /* release ref and remove partner vdev from self list */ 460 dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX); 461 pr_pdev = pr_vdev->pdev; 462 vdev_be->partner_vdev_list[pr_soc_be->mlo_chip_id][pr_pdev->pdev_id] = 463 CDP_INVALID_VDEV_ID; 464 465 dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX); 466 } 467 } 468 } 469 470 static void dp_mlo_setup_complete(struct cdp_mlo_ctxt *cdp_ml_ctxt) 471 { 472 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt); 473 int i; 474 struct dp_soc *soc; 475 struct dp_soc_be *be_soc; 476 QDF_STATUS qdf_status; 477 478 if (!cdp_ml_ctxt) 479 return; 480 481 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) { 482 soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i); 483 484 if (!soc) 485 continue; 486 be_soc = dp_get_be_soc_from_dp_soc(soc); 487 488 qdf_status = dp_partner_soc_rx_hw_cc_init(mlo_ctxt, be_soc); 489 490 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 491 dp_alert("MLO partner SOC Rx desc CC init failed"); 492 qdf_assert_always(0); 493 } 494 } 495 } 496 497 static void dp_mlo_update_delta_tsf2(struct cdp_soc_t *soc_hdl, 498 uint8_t pdev_id, uint64_t delta_tsf2) 499 { 500 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 501 struct dp_pdev *pdev; 502 struct dp_pdev_be *be_pdev; 503 504 pdev = dp_get_pdev_from_soc_pdev_id_wifi3((struct dp_soc *)soc, 505 pdev_id); 506 if (!pdev) { 507 dp_err("pdev is NULL for pdev_id %u", pdev_id); 508 return; 509 } 510 511 be_pdev = dp_get_be_pdev_from_dp_pdev(pdev); 512 513 be_pdev->delta_tsf2 = delta_tsf2; 514 } 515 516 static void dp_mlo_update_delta_tqm(struct cdp_soc_t *soc_hdl, 517 uint64_t delta_tqm) 518 { 519 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 520 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 521 522 be_soc->delta_tqm = delta_tqm; 523 } 524 525 static void dp_mlo_update_mlo_ts_offset(struct cdp_soc_t *soc_hdl, 526 uint64_t offset) 527 { 528 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); 529 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 530 531 be_soc->mlo_tstamp_offset = offset; 532 } 533 534 static struct cdp_mlo_ops dp_mlo_ops = { 535 .mlo_soc_setup = dp_mlo_soc_setup, 536 .mlo_soc_teardown = dp_mlo_soc_teardown, 537 .update_mlo_ptnr_list = dp_update_mlo_ptnr_list, 538 .mlo_setup_complete = dp_mlo_setup_complete, 539 .mlo_update_delta_tsf2 = dp_mlo_update_delta_tsf2, 540 .mlo_update_delta_tqm = dp_mlo_update_delta_tqm, 541 .mlo_update_mlo_ts_offset = dp_mlo_update_mlo_ts_offset, 542 .mlo_ctxt_attach = dp_mlo_ctxt_attach_wifi3, 543 .mlo_ctxt_detach = dp_mlo_ctxt_detach_wifi3, 544 }; 545 546 void dp_soc_mlo_fill_params(struct dp_soc *soc, 547 struct cdp_soc_attach_params *params) 548 { 549 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 550 551 if (!params->mlo_enabled) { 552 dp_warn("MLO not enabled on SOC"); 553 return; 554 } 555 556 be_soc->mlo_chip_id = params->mlo_chip_id; 557 be_soc->ml_ctxt = cdp_mlo_ctx_to_dp(params->ml_context); 558 be_soc->mlo_enabled = 1; 559 soc->cdp_soc.ops->mlo_ops = &dp_mlo_ops; 560 } 561 562 void dp_mlo_update_link_to_pdev_map(struct dp_soc *soc, struct dp_pdev *pdev) 563 { 564 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 565 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev); 566 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 567 uint8_t link_id; 568 569 if (!be_soc->mlo_enabled) 570 return; 571 572 if (!ml_ctxt) 573 return; 574 575 link_id = be_pdev->mlo_link_id; 576 577 if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC) { 578 if (!ml_ctxt->link_to_pdev_map[link_id]) 579 ml_ctxt->link_to_pdev_map[link_id] = be_pdev; 580 else 581 dp_alert("Attempt to update existing map for link %u", 582 link_id); 583 } 584 } 585 586 void dp_mlo_update_link_to_pdev_unmap(struct dp_soc *soc, struct dp_pdev *pdev) 587 { 588 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 589 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev); 590 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 591 uint8_t link_id; 592 593 if (!be_soc->mlo_enabled) 594 return; 595 596 if (!ml_ctxt) 597 return; 598 599 link_id = be_pdev->mlo_link_id; 600 601 if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC) 602 ml_ctxt->link_to_pdev_map[link_id] = NULL; 603 } 604 605 static struct dp_pdev_be * 606 dp_mlo_get_be_pdev_from_link_id(struct dp_mlo_ctxt *ml_ctxt, uint8_t link_id) 607 { 608 if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC) 609 return ml_ctxt->link_to_pdev_map[link_id]; 610 return NULL; 611 } 612 613 void dp_pdev_mlo_fill_params(struct dp_pdev *pdev, 614 struct cdp_pdev_attach_params *params) 615 { 616 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(pdev->soc); 617 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev); 618 619 if (!be_soc->mlo_enabled) { 620 dp_info("MLO not enabled on SOC"); 621 return; 622 } 623 624 be_pdev->mlo_link_id = params->mlo_link_id; 625 } 626 627 void dp_mlo_partner_chips_map(struct dp_soc *soc, 628 struct dp_peer *peer, 629 uint16_t peer_id) 630 { 631 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 632 struct dp_mlo_ctxt *mlo_ctxt = NULL; 633 bool is_ml_peer_id = 634 HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id); 635 uint8_t chip_id; 636 struct dp_soc *temp_soc; 637 638 /* for non ML peer dont map on partner chips*/ 639 if (!is_ml_peer_id) 640 return; 641 642 mlo_ctxt = be_soc->ml_ctxt; 643 if (!mlo_ctxt) 644 return; 645 646 qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock); 647 for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) { 648 temp_soc = mlo_ctxt->ml_soc_list[chip_id]; 649 650 if (!temp_soc) 651 continue; 652 653 /* skip if this is current soc */ 654 if (temp_soc == soc) 655 continue; 656 657 dp_peer_find_id_to_obj_add(temp_soc, peer, peer_id); 658 } 659 qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock); 660 } 661 662 qdf_export_symbol(dp_mlo_partner_chips_map); 663 664 void dp_mlo_partner_chips_unmap(struct dp_soc *soc, 665 uint16_t peer_id) 666 { 667 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 668 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 669 bool is_ml_peer_id = 670 HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id); 671 uint8_t chip_id; 672 struct dp_soc *temp_soc; 673 674 if (!is_ml_peer_id) 675 return; 676 677 if (!mlo_ctxt) 678 return; 679 680 qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock); 681 for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) { 682 temp_soc = mlo_ctxt->ml_soc_list[chip_id]; 683 684 if (!temp_soc) 685 continue; 686 687 /* skip if this is current soc */ 688 if (temp_soc == soc) 689 continue; 690 691 dp_peer_find_id_to_obj_remove(temp_soc, peer_id); 692 } 693 qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock); 694 } 695 696 qdf_export_symbol(dp_mlo_partner_chips_unmap); 697 698 uint8_t dp_mlo_get_chip_id(struct dp_soc *soc) 699 { 700 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 701 702 return be_soc->mlo_chip_id; 703 } 704 705 qdf_export_symbol(dp_mlo_get_chip_id); 706 707 struct dp_peer * 708 dp_link_peer_hash_find_by_chip_id(struct dp_soc *soc, 709 uint8_t *peer_mac_addr, 710 int mac_addr_is_aligned, 711 uint8_t vdev_id, 712 uint8_t chip_id, 713 enum dp_mod_id mod_id) 714 { 715 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 716 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 717 struct dp_soc *link_peer_soc = NULL; 718 struct dp_peer *peer = NULL; 719 720 if (!mlo_ctxt) 721 return NULL; 722 723 link_peer_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id); 724 725 if (!link_peer_soc) 726 return NULL; 727 728 peer = dp_peer_find_hash_find(link_peer_soc, peer_mac_addr, 729 mac_addr_is_aligned, vdev_id, 730 mod_id); 731 qdf_atomic_dec(&link_peer_soc->ref_count); 732 return peer; 733 } 734 735 qdf_export_symbol(dp_link_peer_hash_find_by_chip_id); 736 737 void dp_mlo_get_rx_hash_key(struct dp_soc *soc, 738 struct cdp_lro_hash_config *lro_hash) 739 { 740 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 741 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 742 743 if (!be_soc->mlo_enabled || !ml_ctxt) 744 return dp_get_rx_hash_key_bytes(lro_hash); 745 746 qdf_mem_copy(lro_hash->toeplitz_hash_ipv4, ml_ctxt->toeplitz_hash_ipv4, 747 (sizeof(lro_hash->toeplitz_hash_ipv4[0]) * 748 LRO_IPV4_SEED_ARR_SZ)); 749 qdf_mem_copy(lro_hash->toeplitz_hash_ipv6, ml_ctxt->toeplitz_hash_ipv6, 750 (sizeof(lro_hash->toeplitz_hash_ipv6[0]) * 751 LRO_IPV6_SEED_ARR_SZ)); 752 } 753 754 void dp_mlo_set_rx_fst(struct dp_soc *soc, struct dp_rx_fst *fst) 755 { 756 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 757 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 758 759 if (be_soc->mlo_enabled && ml_ctxt) 760 ml_ctxt->rx_fst = fst; 761 } 762 763 struct dp_rx_fst *dp_mlo_get_rx_fst(struct dp_soc *soc) 764 { 765 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 766 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 767 768 if (be_soc->mlo_enabled && ml_ctxt) 769 return ml_ctxt->rx_fst; 770 771 return NULL; 772 } 773 774 void dp_mlo_rx_fst_ref(struct dp_soc *soc) 775 { 776 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 777 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 778 779 if (be_soc->mlo_enabled && ml_ctxt) 780 ml_ctxt->rx_fst_ref_cnt++; 781 } 782 783 uint8_t dp_mlo_rx_fst_deref(struct dp_soc *soc) 784 { 785 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 786 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 787 uint8_t rx_fst_ref_cnt; 788 789 if (be_soc->mlo_enabled && ml_ctxt) { 790 rx_fst_ref_cnt = ml_ctxt->rx_fst_ref_cnt; 791 ml_ctxt->rx_fst_ref_cnt--; 792 return rx_fst_ref_cnt; 793 } 794 795 return 1; 796 } 797 798 struct dp_soc * 799 dp_rx_replensih_soc_get(struct dp_soc *soc, uint8_t chip_id) 800 { 801 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 802 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 803 struct dp_soc *replenish_soc; 804 805 if (!be_soc->mlo_enabled || !mlo_ctxt) 806 return soc; 807 808 if (be_soc->mlo_chip_id == chip_id) 809 return soc; 810 811 replenish_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id); 812 if (qdf_unlikely(!replenish_soc)) { 813 dp_alert("replenish SOC is NULL"); 814 qdf_assert_always(0); 815 } 816 817 return replenish_soc; 818 } 819 820 uint8_t dp_soc_get_num_soc_be(struct dp_soc *soc) 821 { 822 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 823 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 824 825 if (!be_soc->mlo_enabled || !mlo_ctxt) 826 return 1; 827 828 return mlo_ctxt->ml_soc_cnt; 829 } 830 831 struct dp_soc * 832 dp_soc_get_by_idle_bm_id(struct dp_soc *soc, uint8_t idle_bm_id) 833 { 834 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 835 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt; 836 struct dp_soc *partner_soc = NULL; 837 uint8_t chip_id; 838 839 if (!be_soc->mlo_enabled || !mlo_ctxt) 840 return soc; 841 842 for (chip_id = 0; chip_id < WLAN_MAX_MLO_CHIPS; chip_id++) { 843 partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id); 844 845 if (!partner_soc) 846 continue; 847 848 if (partner_soc->idle_link_bm_id == idle_bm_id) 849 return partner_soc; 850 } 851 852 return NULL; 853 } 854 855 #ifdef WLAN_MCAST_MLO 856 void dp_mcast_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, 857 dp_ptnr_soc_iter_func func, 858 void *arg) 859 { 860 int i = 0; 861 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 862 863 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { 864 struct dp_soc *ptnr_soc = 865 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 866 867 if (!ptnr_soc) 868 continue; 869 (*func)(ptnr_soc, arg); 870 } 871 } 872 873 qdf_export_symbol(dp_mcast_mlo_iter_ptnr_soc); 874 875 void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc, 876 struct dp_vdev_be *be_vdev, 877 dp_ptnr_vdev_iter_func func, 878 void *arg, 879 enum dp_mod_id mod_id) 880 { 881 int i = 0; 882 int j = 0; 883 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 884 885 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { 886 struct dp_soc *ptnr_soc = 887 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 888 889 if (!ptnr_soc) 890 continue; 891 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) { 892 struct dp_vdev *ptnr_vdev; 893 894 ptnr_vdev = dp_vdev_get_ref_by_id( 895 ptnr_soc, 896 be_vdev->partner_vdev_list[i][j], 897 mod_id); 898 if (!ptnr_vdev) 899 continue; 900 (*func)(be_vdev, ptnr_vdev, arg); 901 dp_vdev_unref_delete(ptnr_vdev->pdev->soc, 902 ptnr_vdev, 903 mod_id); 904 } 905 } 906 } 907 908 qdf_export_symbol(dp_mcast_mlo_iter_ptnr_vdev); 909 910 struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc, 911 struct dp_vdev_be *be_vdev, 912 enum dp_mod_id mod_id) 913 { 914 int i = 0; 915 int j = 0; 916 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; 917 918 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { 919 struct dp_soc *ptnr_soc = 920 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); 921 922 if (!ptnr_soc) 923 continue; 924 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) { 925 struct dp_vdev *ptnr_vdev = NULL; 926 struct dp_vdev_be *be_ptnr_vdev = NULL; 927 928 ptnr_vdev = dp_vdev_get_ref_by_id( 929 ptnr_soc, 930 be_vdev->partner_vdev_list[i][j], 931 mod_id); 932 if (!ptnr_vdev) 933 continue; 934 be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev); 935 if (be_ptnr_vdev->mcast_primary) 936 return ptnr_vdev; 937 dp_vdev_unref_delete(be_ptnr_vdev->vdev.pdev->soc, 938 &be_ptnr_vdev->vdev, 939 mod_id); 940 } 941 } 942 return NULL; 943 } 944 945 qdf_export_symbol(dp_mlo_get_mcast_primary_vdev); 946 #endif 947 948 static inline uint64_t dp_mlo_get_mlo_ts_offset(struct dp_pdev_be *be_pdev) 949 { 950 struct dp_soc *soc; 951 struct dp_pdev *pdev; 952 struct dp_soc_be *be_soc; 953 uint32_t mlo_offset; 954 955 pdev = &be_pdev->pdev; 956 soc = pdev->soc; 957 be_soc = dp_get_be_soc_from_dp_soc(soc); 958 959 mlo_offset = be_soc->mlo_tstamp_offset; 960 961 return mlo_offset; 962 } 963 964 int32_t dp_mlo_get_delta_tsf2_wrt_mlo_offset(struct dp_soc *soc, 965 uint8_t hw_link_id) 966 { 967 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 968 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt; 969 struct dp_pdev_be *be_pdev; 970 int32_t delta_tsf2_mlo_offset; 971 int32_t mlo_offset, delta_tsf2; 972 973 if (!ml_ctxt) 974 return 0; 975 976 be_pdev = dp_mlo_get_be_pdev_from_link_id(ml_ctxt, hw_link_id); 977 if (!be_pdev) 978 return 0; 979 980 mlo_offset = dp_mlo_get_mlo_ts_offset(be_pdev); 981 delta_tsf2 = be_pdev->delta_tsf2; 982 983 delta_tsf2_mlo_offset = mlo_offset - delta_tsf2; 984 985 return delta_tsf2_mlo_offset; 986 } 987 988 int32_t dp_mlo_get_delta_tqm_wrt_mlo_offset(struct dp_soc *soc) 989 { 990 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); 991 int32_t delta_tqm_mlo_offset; 992 int32_t mlo_offset, delta_tqm; 993 994 mlo_offset = be_soc->mlo_tstamp_offset; 995 delta_tqm = be_soc->delta_tqm; 996 997 delta_tqm_mlo_offset = mlo_offset - delta_tqm; 998 999 return delta_tqm_mlo_offset; 1000 } 1001