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 #include "wlan_mlo_mgr_main.h" 19 #include "qdf_types.h" 20 #include "wlan_cmn.h" 21 #include "wlan_mlo_mgr_peer.h" 22 #include <wlan_mlo_mgr_ap.h> 23 #include <wlan_mlo_mgr_setup.h> 24 #include <wlan_utility.h> 25 #include <wlan_reg_services_api.h> 26 27 /** 28 * struct mlpeer_data: PSOC peers MLO data 29 * @total_rssi: sum of RSSI of all ML peers 30 * @num_ml_peers: Number of ML peer's with this PSOC as TQM 31 * @max_ml_peers: Max ML peers can have this PSOC as TQM 32 * (it is to distribute peers across all PSOCs) 33 * @num_non_ml_peers: Non MLO peers of this PSOC 34 */ 35 struct mlpeer_data { 36 int32_t total_rssi; 37 uint16_t num_ml_peers; 38 uint16_t max_ml_peers; 39 uint16_t num_non_ml_peers; 40 }; 41 42 /** 43 * struct mlo_all_link_rssi: structure to collect TQM params for all PSOCs 44 * @psoc_tqm_parms: It collects peer data for all PSOCs 45 * @num_psocs: Number of PSOCs in the system 46 * @current_psoc_id: current psoc id, it is for iterator 47 */ 48 struct mlo_all_link_rssi { 49 struct mlpeer_data psoc_tqm_parms[WLAN_OBJMGR_MAX_DEVICES]; 50 uint8_t num_psocs; 51 uint8_t current_psoc_id; 52 }; 53 54 /* Invalid TQM/PSOC ID */ 55 #define ML_INVALID_PRIMARY_TQM 0xff 56 /* Congestion value */ 57 #define ML_PRIMARY_TQM_CONGESTION 30 58 /* PTQM migration timeout value in ms */ 59 #define ML_PRIMARY_TQM_MIGRATRION_TIMEOUT 4000 60 61 static void wlan_mlo_peer_get_rssi(struct wlan_objmgr_psoc *psoc, 62 void *obj, void *args) 63 { 64 struct wlan_mlo_peer_context *mlo_peer_ctx; 65 struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)obj; 66 struct mlo_all_link_rssi *rssi_data = (struct mlo_all_link_rssi *)args; 67 struct mlpeer_data *tqm_params = NULL; 68 uint8_t index; 69 70 mlo_peer_ctx = peer->mlo_peer_ctx; 71 index = rssi_data->current_psoc_id; 72 tqm_params = &rssi_data->psoc_tqm_parms[index]; 73 74 if (!wlan_peer_is_mlo(peer) && !mlo_peer_ctx) { 75 if (wlan_peer_get_peer_type(peer) == WLAN_PEER_STA) 76 tqm_params->num_non_ml_peers += 1; 77 return; 78 } 79 80 if (!mlo_peer_ctx) 81 return; 82 83 /* If this psoc is new primary UMAC after migration, 84 * account RSSI on new link 85 */ 86 if (mlo_peer_ctx->migrate_primary_umac_psoc_id == 87 rssi_data->current_psoc_id) { 88 tqm_params->total_rssi += mlo_peer_ctx->avg_link_rssi; 89 tqm_params->num_ml_peers += 1; 90 return; 91 } 92 93 /* If this psoc is not primary UMAC or if TQM migration is happening 94 * from current primary psoc, don't account RSSI 95 */ 96 if (mlo_peer_ctx->primary_umac_psoc_id == rssi_data->current_psoc_id && 97 mlo_peer_ctx->migrate_primary_umac_psoc_id == 98 ML_INVALID_PRIMARY_TQM) { 99 tqm_params->total_rssi += mlo_peer_ctx->avg_link_rssi; 100 tqm_params->num_ml_peers += 1; 101 } 102 } 103 104 static void wlan_get_rssi_data_each_psoc(struct wlan_objmgr_psoc *psoc, 105 void *arg, uint8_t index) 106 { 107 struct mlo_all_link_rssi *rssi_data = (struct mlo_all_link_rssi *)arg; 108 struct mlpeer_data *tqm_params = NULL; 109 110 tqm_params = &rssi_data->psoc_tqm_parms[index]; 111 112 tqm_params->total_rssi = 0; 113 tqm_params->num_ml_peers = 0; 114 tqm_params->num_non_ml_peers = 0; 115 tqm_params->max_ml_peers = MAX_MLO_PEER; 116 117 rssi_data->current_psoc_id = index; 118 rssi_data->num_psocs++; 119 120 wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP, 121 wlan_mlo_peer_get_rssi, rssi_data, 0, 122 WLAN_MLO_MGR_ID); 123 } 124 125 static QDF_STATUS mld_get_link_rssi(struct mlo_all_link_rssi *rssi_data) 126 { 127 rssi_data->num_psocs = 0; 128 129 wlan_objmgr_iterate_psoc_list(wlan_get_rssi_data_each_psoc, 130 rssi_data, WLAN_MLO_MGR_ID); 131 132 return QDF_STATUS_SUCCESS; 133 } 134 135 uint8_t 136 wlan_mld_get_best_primary_umac_w_rssi(struct wlan_mlo_peer_context *ml_peer, 137 struct wlan_objmgr_vdev *link_vdevs[], 138 bool allow_all_links) 139 { 140 struct mlo_all_link_rssi rssi_data; 141 uint8_t i; 142 int32_t avg_rssi[WLAN_OBJMGR_MAX_DEVICES] = {0}; 143 int32_t diff_rssi[WLAN_OBJMGR_MAX_DEVICES] = {0}; 144 int32_t diff_low; 145 bool mld_sta_links[WLAN_OBJMGR_MAX_DEVICES] = {0}; 146 bool mld_no_sta[WLAN_OBJMGR_MAX_DEVICES] = {0}; 147 uint8_t prim_link, id, prim_link_hi; 148 uint8_t num_psocs; 149 struct mlpeer_data *tqm_params = NULL; 150 struct wlan_channel *channel; 151 enum phy_ch_width sec_hi_bw, hi_bw; 152 uint8_t cong = ML_PRIMARY_TQM_CONGESTION; 153 uint16_t mld_ml_sta_count[WLAN_OBJMGR_MAX_DEVICES] = {0}; 154 enum phy_ch_width mld_ch_width[WLAN_OBJMGR_MAX_DEVICES]; 155 uint8_t psoc_w_nosta; 156 uint16_t ml_sta_count = 0; 157 uint32_t total_cap, cap; 158 uint16_t bw; 159 bool group_full[WLAN_OBJMGR_MAX_DEVICES] = {0}; 160 uint16_t group_size[WLAN_OBJMGR_MAX_DEVICES] = {0}; 161 uint16_t grp_size = 0; 162 uint16_t group_full_count = 0; 163 164 mld_get_link_rssi(&rssi_data); 165 166 for (i = 0; i < rssi_data.num_psocs; i++) { 167 tqm_params = &rssi_data.psoc_tqm_parms[i]; 168 169 if (tqm_params->num_ml_peers) 170 avg_rssi[i] = (tqm_params->total_rssi / 171 tqm_params->num_ml_peers); 172 } 173 174 /** 175 * If MLD STA associated to a set of links, choose primary UMAC 176 * from those links only 177 */ 178 num_psocs = 0; 179 psoc_w_nosta = 0; 180 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) 181 mld_ch_width[i] = CH_WIDTH_INVALID; 182 183 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 184 if (!link_vdevs[i]) 185 continue; 186 187 id = wlan_vdev_get_psoc_id(link_vdevs[i]); 188 if (id >= WLAN_OBJMGR_MAX_DEVICES) 189 continue; 190 191 if (!allow_all_links && wlan_vdev_skip_pumac(link_vdevs[i])) { 192 mlo_err("Skip Radio for Primary MLO umac"); 193 mld_sta_links[id] = false; 194 continue; 195 } 196 197 tqm_params = &rssi_data.psoc_tqm_parms[id]; 198 mld_sta_links[id] = true; 199 200 channel = wlan_vdev_mlme_get_bss_chan(link_vdevs[i]); 201 mld_ch_width[id] = channel->ch_width; 202 203 if ((tqm_params->num_ml_peers + 204 tqm_params->num_non_ml_peers) == 0) { 205 /* If this PSOC has no stations */ 206 mld_no_sta[id] = true; 207 psoc_w_nosta++; 208 } 209 210 mld_ml_sta_count[id] = tqm_params->num_ml_peers; 211 /* Update total MLO STA count */ 212 ml_sta_count += tqm_params->num_ml_peers; 213 214 num_psocs++; 215 216 /* If no stations are associated, derive diff rssi 217 * based on psoc id {0-20, 20-40, 40 } so that 218 * stations are distributed across TQMs 219 */ 220 if (!avg_rssi[id]) { 221 diff_rssi[id] = (id * 20); 222 continue; 223 } 224 diff_rssi[id] = (ml_peer->avg_link_rssi >= avg_rssi[id]) ? 225 (ml_peer->avg_link_rssi - avg_rssi[id]) : 226 (avg_rssi[id] - ml_peer->avg_link_rssi); 227 228 } 229 230 prim_link = ML_INVALID_PRIMARY_TQM; 231 232 /* If one of the PSOCs doesn't have any station select that PSOC as 233 * primary TQM. If more than one PSOC have no stations as Primary TQM 234 * the vdev with less bw needs to be selected as Primary TQM 235 */ 236 if (psoc_w_nosta == 1) { 237 for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) { 238 if (mld_no_sta[i]) { 239 prim_link = i; 240 break; 241 } 242 } 243 } else if (psoc_w_nosta > 1) { 244 hi_bw = CH_WIDTH_INVALID; 245 sec_hi_bw = CH_WIDTH_INVALID; 246 for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) { 247 if (!mld_no_sta[i]) 248 continue; 249 250 if (hi_bw == CH_WIDTH_INVALID) { 251 prim_link_hi = i; 252 hi_bw = mld_ch_width[i]; 253 continue; 254 } 255 /* if bw is 320MHZ mark it as highest ch width */ 256 if (mld_ch_width[i] == CH_WIDTH_320MHZ) { 257 prim_link = prim_link_hi; 258 sec_hi_bw = hi_bw; 259 hi_bw = mld_ch_width[i]; 260 prim_link_hi = i; 261 } 262 /* If bw is less than or equal to 160 MHZ 263 * and chwidth is greater than than other link 264 * Mark this link as primary link 265 */ 266 if (mld_ch_width[i] <= CH_WIDTH_160MHZ) { 267 if (hi_bw < mld_ch_width[i]) { 268 /* move high bw to second high bw */ 269 prim_link = prim_link_hi; 270 sec_hi_bw = hi_bw; 271 272 hi_bw = mld_ch_width[i]; 273 prim_link_hi = i; 274 } else if ((sec_hi_bw == CH_WIDTH_INVALID) || 275 (sec_hi_bw < mld_ch_width[i])) { 276 /* update sec high bw */ 277 sec_hi_bw = mld_ch_width[i]; 278 prim_link = i; 279 } 280 } 281 } 282 } else { 283 total_cap = 0; 284 for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) { 285 bw = wlan_reg_get_bw_value(mld_ch_width[i]); 286 total_cap += bw * (100 - cong); 287 } 288 289 group_full_count = 0; 290 for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) { 291 if (!mld_sta_links[i]) 292 continue; 293 294 bw = wlan_reg_get_bw_value(mld_ch_width[i]); 295 cap = bw * (100 - cong); 296 grp_size = (ml_sta_count) * ((cap * 100) / total_cap); 297 group_size[i] = grp_size / 100; 298 if (group_size[i] <= mld_ml_sta_count[i]) { 299 group_full[i] = true; 300 group_full_count++; 301 } 302 } 303 304 if ((num_psocs - group_full_count) == 1) { 305 for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) { 306 if (!mld_sta_links[i]) 307 continue; 308 309 if (group_full[i]) 310 continue; 311 312 prim_link = i; 313 break; 314 } 315 } else { 316 diff_low = 0; 317 /* find min diff, based on it, allocate primary umac */ 318 for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) { 319 if (!mld_sta_links[i]) 320 continue; 321 322 /* First iteration */ 323 if (diff_low == 0) { 324 diff_low = diff_rssi[i]; 325 prim_link = i; 326 } else if (diff_low > diff_rssi[i]) { 327 diff_low = diff_rssi[i]; 328 prim_link = i; 329 } 330 } 331 } 332 } 333 334 if (prim_link != ML_INVALID_PRIMARY_TQM) 335 return prim_link; 336 337 /* If primary link id is not found, return id of 1st available link */ 338 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 339 if (!link_vdevs[i]) 340 continue; 341 342 if (!allow_all_links && wlan_vdev_skip_pumac(link_vdevs[i])) { 343 mlo_debug("Skip Radio for Primary MLO umac"); 344 continue; 345 } 346 id = wlan_vdev_get_psoc_id(link_vdevs[i]); 347 if (id >= WLAN_OBJMGR_MAX_DEVICES) 348 continue; 349 350 return wlan_vdev_get_psoc_id(link_vdevs[i]); 351 } 352 353 return ML_INVALID_PRIMARY_TQM; 354 } 355 356 void mlo_peer_assign_primary_umac( 357 struct wlan_mlo_peer_context *ml_peer, 358 struct wlan_mlo_link_peer_entry *peer_entry) 359 { 360 struct wlan_mlo_link_peer_entry *peer_ent_iter; 361 uint8_t i; 362 uint8_t primary_umac_set = 0; 363 364 /* If MLD is within single SOC, then assoc link becomes 365 * primary umac 366 */ 367 if (ml_peer->primary_umac_psoc_id == ML_PRIMARY_UMAC_ID_INVAL) { 368 if (wlan_peer_mlme_is_assoc_peer(peer_entry->link_peer)) { 369 peer_entry->is_primary = true; 370 ml_peer->primary_umac_psoc_id = 371 wlan_peer_get_psoc_id(peer_entry->link_peer); 372 } else { 373 peer_entry->is_primary = false; 374 } 375 } else { 376 /* If this peer PSOC is not derived as Primary PSOC, 377 * mark is_primary as false 378 */ 379 if (wlan_peer_get_psoc_id(peer_entry->link_peer) != 380 ml_peer->primary_umac_psoc_id) { 381 peer_entry->is_primary = false; 382 return; 383 } 384 385 /* For single SOC, check whether is_primary is set for 386 * other partner peer, then mark is_primary false for this peer 387 */ 388 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 389 peer_ent_iter = &ml_peer->peer_list[i]; 390 391 if (!peer_ent_iter->link_peer) 392 continue; 393 394 /* Check for other link peers */ 395 if (peer_ent_iter == peer_entry) 396 continue; 397 398 if (wlan_peer_get_psoc_id(peer_ent_iter->link_peer) != 399 ml_peer->primary_umac_psoc_id) 400 continue; 401 402 if (peer_ent_iter->is_primary) 403 primary_umac_set = 1; 404 } 405 406 if (primary_umac_set) 407 peer_entry->is_primary = false; 408 else 409 peer_entry->is_primary = true; 410 } 411 } 412 413 static int8_t wlan_vdev_derive_link_rssi(struct wlan_objmgr_vdev *vdev, 414 struct wlan_objmgr_vdev *assoc_vdev, 415 int8_t rssi) 416 { 417 struct wlan_channel *channel, *assoc_channel; 418 uint16_t ch_freq, assoc_freq; 419 uint8_t tx_pow, assoc_tx_pow; 420 int8_t diff_txpow; 421 struct wlan_objmgr_pdev *pdev, *assoc_pdev; 422 uint8_t log10_freq; 423 uint8_t derived_rssi; 424 int16_t ten_derived_rssi; 425 int8_t ten_diff_pl = 0; 426 427 pdev = wlan_vdev_get_pdev(vdev); 428 assoc_pdev = wlan_vdev_get_pdev(assoc_vdev); 429 430 channel = wlan_vdev_get_active_channel(vdev); 431 if (channel) 432 ch_freq = channel->ch_freq; 433 else 434 ch_freq = 1; 435 436 assoc_channel = wlan_vdev_get_active_channel(assoc_vdev); 437 if (assoc_channel) 438 assoc_freq = assoc_channel->ch_freq; 439 else 440 assoc_freq = 1; 441 442 /* 443 * diff of path loss (of two links) = log10(freq1) - log10(freq2) 444 * (since distance is constant) 445 * since log10 is not available, we cameup with approximate ranges 446 */ 447 log10_freq = (ch_freq * 10) / assoc_freq; 448 if ((log10_freq >= 20) && (log10_freq < 30)) 449 ten_diff_pl = 4; /* 0.4 *10 */ 450 else if ((log10_freq >= 11) && (log10_freq < 20)) 451 ten_diff_pl = 1; /* 0.1 *10 */ 452 else if ((log10_freq >= 8) && (log10_freq < 11)) 453 ten_diff_pl = 0; /* 0 *10 */ 454 else if ((log10_freq >= 4) && (log10_freq < 8)) 455 ten_diff_pl = -1; /* -0.1 * 10 */ 456 else if ((log10_freq >= 1) && (log10_freq < 4)) 457 ten_diff_pl = -4; /* -0.4 * 10 */ 458 459 assoc_tx_pow = wlan_reg_get_channel_reg_power_for_freq(assoc_pdev, 460 assoc_freq); 461 tx_pow = wlan_reg_get_channel_reg_power_for_freq(pdev, ch_freq); 462 463 diff_txpow = tx_pow - assoc_tx_pow; 464 465 ten_derived_rssi = (diff_txpow * 10) - ten_diff_pl + (rssi * 10); 466 derived_rssi = ten_derived_rssi / 10; 467 468 return derived_rssi; 469 } 470 471 static void mlo_peer_calculate_avg_rssi( 472 struct wlan_mlo_dev_context *ml_dev, 473 struct wlan_mlo_peer_context *ml_peer, 474 int8_t rssi, 475 struct wlan_objmgr_vdev *assoc_vdev) 476 { 477 int32_t total_rssi = 0; 478 uint8_t num_psocs = 0; 479 uint8_t i; 480 struct wlan_objmgr_vdev *vdev; 481 482 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 483 vdev = ml_dev->wlan_vdev_list[i]; 484 if (!vdev) 485 continue; 486 487 num_psocs++; 488 if (vdev == assoc_vdev) 489 total_rssi += rssi; 490 else 491 total_rssi += wlan_vdev_derive_link_rssi(vdev, 492 assoc_vdev, 493 rssi); 494 } 495 496 if (!num_psocs) 497 return; 498 499 ml_peer->avg_link_rssi = total_rssi / num_psocs; 500 } 501 502 #ifdef WLAN_MLO_MULTI_CHIP 503 int8_t mlo_get_central_umac_id( 504 uint8_t *psoc_ids) 505 { 506 uint8_t prim_psoc_id = -1; 507 uint8_t adjacent = 0; 508 509 /* Some 3 link RDPs have restriction on the primary umac. 510 * Only the link that is adjacent to both the links can be 511 * a primary umac. 512 * Note: it means umac migration is also restricted. 513 */ 514 mlo_chip_adjacent(psoc_ids[0], psoc_ids[1], &adjacent); 515 if (!adjacent) { 516 prim_psoc_id = psoc_ids[2]; 517 } else { 518 mlo_chip_adjacent(psoc_ids[0], psoc_ids[2], &adjacent); 519 if (!adjacent) { 520 prim_psoc_id = psoc_ids[1]; 521 } else { 522 /* If all links are adjacent to each other, 523 * no need to restrict the primary umac. 524 * return failure the caller will handle. 525 */ 526 mlo_chip_adjacent(psoc_ids[1], psoc_ids[2], 527 &adjacent); 528 if (!adjacent) 529 prim_psoc_id = psoc_ids[0]; 530 else 531 return prim_psoc_id; 532 } 533 } 534 535 return prim_psoc_id; 536 } 537 538 static QDF_STATUS mlo_set_3_link_primary_umac( 539 struct wlan_mlo_peer_context *ml_peer, 540 struct wlan_objmgr_vdev *link_vdevs[]) 541 { 542 uint8_t psoc_ids[WLAN_UMAC_MLO_MAX_VDEVS]; 543 int8_t central_umac_id; 544 545 if (ml_peer->max_links != 3) 546 return QDF_STATUS_E_FAILURE; 547 548 /* Some 3 link RDPs have restriction on the primary umac. 549 * Only the link that is adjacent to both the links can be 550 * a primary umac. 551 * Note: it means umac migration is also restricted. 552 */ 553 psoc_ids[0] = wlan_vdev_get_psoc_id(link_vdevs[0]); 554 psoc_ids[1] = wlan_vdev_get_psoc_id(link_vdevs[1]); 555 psoc_ids[2] = wlan_vdev_get_psoc_id(link_vdevs[2]); 556 557 central_umac_id = mlo_get_central_umac_id(psoc_ids); 558 if (central_umac_id != -1) 559 ml_peer->primary_umac_psoc_id = central_umac_id; 560 else 561 return QDF_STATUS_E_FAILURE; 562 563 mlo_peer_assign_primary_umac(ml_peer, 564 &ml_peer->peer_list[0]); 565 566 return QDF_STATUS_SUCCESS; 567 } 568 #else 569 static QDF_STATUS mlo_set_3_link_primary_umac( 570 struct wlan_mlo_peer_context *ml_peer, 571 struct wlan_objmgr_vdev *link_vdevs[]) 572 { 573 return QDF_STATUS_E_FAILURE; 574 } 575 #endif 576 577 QDF_STATUS mlo_peer_allocate_primary_umac( 578 struct wlan_mlo_dev_context *ml_dev, 579 struct wlan_mlo_peer_context *ml_peer, 580 struct wlan_objmgr_vdev *link_vdevs[]) 581 { 582 struct wlan_mlo_link_peer_entry *peer_entry; 583 struct wlan_objmgr_peer *assoc_peer = NULL; 584 int32_t rssi; 585 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 586 uint8_t first_link_id = 0; 587 bool primary_umac_set = false; 588 uint8_t i, psoc_id; 589 590 peer_entry = &ml_peer->peer_list[0]; 591 assoc_peer = peer_entry->link_peer; 592 if (!assoc_peer) 593 return QDF_STATUS_E_FAILURE; 594 595 /* For Station mode, assign assoc peer as primary umac */ 596 if (wlan_peer_get_peer_type(assoc_peer) == WLAN_PEER_AP) { 597 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 598 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ", 599 ml_dev->mld_id, 600 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 601 ml_peer->primary_umac_psoc_id); 602 603 return QDF_STATUS_SUCCESS; 604 } 605 606 /* Select assoc peer's PSOC as primary UMAC in Multi-chip solution, 607 * 1) for single link MLO connection 608 * 2) if MLD is single chip MLO 609 */ 610 if ((mlo_ctx->force_non_assoc_prim_umac) && 611 (ml_peer->max_links >= 1)) { 612 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 613 if (!link_vdevs[i]) 614 continue; 615 616 if (wlan_peer_get_vdev(assoc_peer) == link_vdevs[i]) 617 continue; 618 psoc_id = wlan_vdev_get_psoc_id(link_vdevs[i]); 619 ml_peer->primary_umac_psoc_id = psoc_id; 620 break; 621 } 622 623 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 624 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT 625 " primary umac soc %d ", ml_dev->mld_id, 626 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 627 ml_peer->primary_umac_psoc_id); 628 629 return QDF_STATUS_SUCCESS; 630 } 631 632 if ((ml_peer->max_links == 1) || 633 (mlo_vdevs_check_single_soc(link_vdevs, ml_peer->max_links))) { 634 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 635 mlo_info("MLD ID %d Assoc peer " QDF_MAC_ADDR_FMT 636 " primary umac soc %d ", ml_dev->mld_id, 637 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 638 ml_peer->primary_umac_psoc_id); 639 640 return QDF_STATUS_SUCCESS; 641 } 642 643 if (mlo_set_3_link_primary_umac(ml_peer, link_vdevs) == 644 QDF_STATUS_SUCCESS) { 645 /* If success then the primary umac is restricted and assigned. 646 * if not, there is no restriction, so just fallthrough 647 */ 648 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT 649 " center primary umac soc %d ", 650 ml_dev->mld_id, 651 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 652 ml_peer->primary_umac_psoc_id); 653 654 return QDF_STATUS_SUCCESS; 655 } 656 657 if (mlo_ctx->mlo_is_force_primary_umac) { 658 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 659 if (!link_vdevs[i]) 660 continue; 661 662 psoc_id = wlan_vdev_get_psoc_id(link_vdevs[i]); 663 if (!first_link_id) 664 first_link_id = psoc_id; 665 666 if (psoc_id == mlo_ctx->mlo_forced_primary_umac_id) { 667 ml_peer->primary_umac_psoc_id = psoc_id; 668 primary_umac_set = true; 669 break; 670 } 671 } 672 673 if (!primary_umac_set) 674 ml_peer->primary_umac_psoc_id = first_link_id; 675 676 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 677 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ", 678 ml_dev->mld_id, 679 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 680 ml_peer->primary_umac_psoc_id); 681 682 return QDF_STATUS_SUCCESS; 683 } 684 685 rssi = wlan_peer_get_rssi(assoc_peer); 686 mlo_peer_calculate_avg_rssi(ml_dev, ml_peer, rssi, 687 wlan_peer_get_vdev(assoc_peer)); 688 689 ml_peer->primary_umac_psoc_id = 690 wlan_mld_get_best_primary_umac_w_rssi(ml_peer, link_vdevs, false); 691 692 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 693 694 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " avg RSSI %d primary umac soc %d ", 695 ml_dev->mld_id, 696 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 697 ml_peer->avg_link_rssi, ml_peer->primary_umac_psoc_id); 698 699 return QDF_STATUS_SUCCESS; 700 } 701 702 QDF_STATUS mlo_peer_free_primary_umac( 703 struct wlan_mlo_dev_context *ml_dev, 704 struct wlan_mlo_peer_context *ml_peer) 705 { 706 return QDF_STATUS_SUCCESS; 707 } 708 709 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE 710 void wlan_objmgr_mlo_update_primary_info(struct wlan_objmgr_peer *peer) 711 { 712 struct wlan_mlo_peer_context *ml_peer = NULL; 713 struct wlan_mlo_link_peer_entry *peer_ent_iter; 714 uint8_t i; 715 716 ml_peer = peer->mlo_peer_ctx; 717 ml_peer->primary_umac_psoc_id = wlan_peer_get_psoc_id(peer); 718 719 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 720 peer_ent_iter = &ml_peer->peer_list[i]; 721 722 if (!peer_ent_iter->link_peer) 723 continue; 724 725 if (peer_ent_iter->is_primary) 726 peer_ent_iter->is_primary = false; 727 728 if (peer_ent_iter->link_peer == peer) 729 peer_ent_iter->is_primary = true; 730 } 731 } 732 733 qdf_export_symbol(wlan_objmgr_mlo_update_primary_info); 734 735 void mlo_mlme_ptqm_migrate_timer_cb(void *arg) 736 { 737 struct wlan_mlo_dev_context *ml_dev = (struct wlan_mlo_dev_context *)arg; 738 struct wlan_mlo_peer_context *ml_peer = NULL; 739 uint16_t i = 0; 740 741 if (!ml_dev) 742 return; 743 744 /* Check for pending bitmaps and issue disconnect */ 745 for (i = 0; i < MAX_MLO_PEER_ID; i++) { 746 if (qdf_test_bit(i, ml_dev->mlo_peer_id_bmap)) { 747 ml_peer = wlan_mlo_get_mlpeer_by_ml_peerid(ml_dev, i); 748 if (ml_peer && ml_peer->primary_umac_migration_in_progress) { 749 ml_peer->primary_umac_migration_in_progress = false; 750 mlo_err("Issue disconnect for ml peer with ml peer id:%d", i); 751 wlan_mlo_peer_deauth_init(ml_peer, 752 NULL, 0); 753 } 754 qdf_clear_bit(i, ml_dev->mlo_peer_id_bmap); 755 } 756 } 757 } 758 759 /** 760 * mlo_ptqm_list_peek_head() - Returns the head of linked list 761 * 762 * @ptqm_list: Pointer to the list of peer ptqm migrate entries 763 * 764 * API to retrieve the head from the list of peer ptqm migrate entries 765 * 766 * Return: Pointer to peer ptqm migrate entry 767 */ 768 static 769 struct peer_ptqm_migrate_list_entry *mlo_ptqm_list_peek_head( 770 qdf_list_t *ptqm_list) 771 { 772 struct peer_ptqm_migrate_list_entry *peer_entry; 773 qdf_list_node_t *peer_node = NULL; 774 775 if (qdf_list_peek_front(ptqm_list, &peer_node) != QDF_STATUS_SUCCESS) 776 return NULL; 777 778 peer_entry = qdf_container_of(peer_node, 779 struct peer_ptqm_migrate_list_entry, 780 node); 781 782 return peer_entry; 783 } 784 785 /** 786 * mlo_get_next_peer_ctx() - Return next peer ptqm entry from the list 787 * 788 * @peer_list: Pointer to the list of peer ptqm migrate entries 789 * @peer_cur: Pointer to the current peer ptqm entry 790 * 791 * API to retrieve the next node from the list of peer ptqm migrate entries 792 * 793 * Return: Pointer to peer ptqm migrate entry 794 */ 795 static 796 struct peer_ptqm_migrate_list_entry *mlo_get_next_peer_ctx( 797 qdf_list_t *peer_list, 798 struct peer_ptqm_migrate_list_entry *peer_cur) 799 { 800 struct peer_ptqm_migrate_list_entry *peer_next; 801 qdf_list_node_t *node = &peer_cur->node; 802 qdf_list_node_t *next_node = NULL; 803 804 /* This API is invoked with lock acquired, do not add log prints */ 805 if (!node) 806 return NULL; 807 808 if (qdf_list_peek_next(peer_list, node, &next_node) != 809 QDF_STATUS_SUCCESS) 810 return NULL; 811 812 peer_next = qdf_container_of(next_node, 813 struct peer_ptqm_migrate_list_entry, 814 node); 815 return peer_next; 816 } 817 818 /** 819 * wlan_mlo_send_ptqm_migrate_cmd() - API to send WMI to trigger ptqm migration 820 * @vdev: objmgr vdev object 821 * @list: peer list to be migrated 822 * @num_peers_failed: number of peers for which wmi cmd is failed. 823 * This value is expected to be used only in case failure is returned by WMI 824 * 825 * API to send WMI to trigger ptqm migration 826 * 827 * Return: QDF_STATUS 828 */ 829 static QDF_STATUS 830 wlan_mlo_send_ptqm_migrate_cmd(struct wlan_objmgr_vdev *vdev, 831 struct peer_migrate_ptqm_multi_entries *list, 832 uint16_t *num_peers_failed) 833 { 834 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 835 struct wlan_objmgr_psoc *psoc; 836 QDF_STATUS status; 837 struct peer_ptqm_migrate_params param = {0}; 838 struct peer_ptqm_migrate_entry *peer_list = NULL; 839 struct peer_ptqm_migrate_list_entry *peer_entry, *next_entry; 840 struct wlan_mlo_dev_context *ml_dev = NULL; 841 uint16_t i = 0; 842 843 ml_dev = vdev->mlo_dev_ctx; 844 if (!ml_dev) 845 return QDF_STATUS_E_FAILURE; 846 847 psoc = wlan_vdev_get_psoc(vdev); 848 if (!psoc) { 849 mlo_err("null psoc"); 850 return QDF_STATUS_E_NULL_VALUE; 851 } 852 853 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 854 if (!mlo_tx_ops || !mlo_tx_ops->peer_ptqm_migrate_send) { 855 mlo_err("mlo_tx_ops is null!"); 856 return QDF_STATUS_E_NULL_VALUE; 857 } 858 859 param.vdev_id = wlan_vdev_get_id(vdev); 860 param.num_peers = list->num_entries; 861 862 param.peer_list = qdf_mem_malloc(sizeof(struct peer_ptqm_migrate_entry) * 863 list->num_entries); 864 if (!param.peer_list) { 865 mlo_err("Failed to allocate memory for ptqm migration command"); 866 return QDF_STATUS_E_FAILURE; 867 } 868 869 peer_list = param.peer_list; 870 871 peer_entry = mlo_ptqm_list_peek_head(&list->peer_list); 872 while (peer_entry) { 873 peer_list[i].ml_peer_id = peer_entry->mlo_peer_id; 874 peer_list[i].hw_link_id = peer_entry->new_hw_link_id; 875 876 qdf_set_bit(peer_entry->mlo_peer_id, 877 ml_dev->mlo_peer_id_bmap); 878 879 mlo_debug("idx:%d, ml_peer_id:%d, hw_link_id:%d", 880 i, peer_list[i].ml_peer_id, 881 peer_list[i].hw_link_id); 882 i++; 883 next_entry = mlo_get_next_peer_ctx(&list->peer_list, 884 peer_entry); 885 peer_entry = next_entry; 886 } 887 888 status = mlo_tx_ops->peer_ptqm_migrate_send(vdev, ¶m); 889 if (QDF_IS_STATUS_ERROR(status)) { 890 mlo_err("Failed to send WMI for ptqm migration"); 891 *num_peers_failed = param.num_peers_failed; 892 qdf_mem_free(param.peer_list); 893 return QDF_STATUS_E_FAILURE; 894 } 895 896 /* Set timeout equal to peer delete timeout as requested by FW. 897 * Timeout value to be optimized later. Timeout value will be 898 * updated later based on stress testings. 899 */ 900 qdf_timer_mod(&ml_dev->ptqm_migrate_timer, 901 ML_PRIMARY_TQM_MIGRATRION_TIMEOUT); 902 903 qdf_mem_free(param.peer_list); 904 return QDF_STATUS_SUCCESS; 905 } 906 907 /** 908 * wlan_mlo_get_new_ptqm_id() - API to get new ptqm ID 909 * @curr_vdev: objmgr vdev object for current primary link 910 * @ml_peer: ml peer object 911 * @new_primary_link_id: new primary link id 912 * @new_hw_link_id: hw link id for new primary TQM 913 * @force_mig: allow migration to vdevs which are disabled to be pumac 914 * using primary_umac_skip ini 915 * 916 * API to get new ptqm ID 917 * 918 * Return: QDF_STATUS 919 */ 920 static QDF_STATUS 921 wlan_mlo_get_new_ptqm_id(struct wlan_objmgr_vdev *curr_vdev, 922 struct wlan_mlo_peer_context *ml_peer, 923 uint8_t new_primary_link_id, 924 uint16_t *new_hw_link_id, 925 bool force_mig) 926 { 927 uint8_t current_primary_link_id = WLAN_LINK_ID_INVALID; 928 struct wlan_objmgr_vdev *tmp_vdev = NULL; 929 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL }; 930 struct wlan_objmgr_vdev *tmp_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL }; 931 struct wlan_mlo_link_peer_entry *peer_entry; 932 uint8_t psoc_ids[WLAN_UMAC_MLO_MAX_VDEVS]; 933 struct wlan_objmgr_vdev *link_vdev = NULL; 934 QDF_STATUS status; 935 uint8_t i = 0, idx = 0, j = 0, tmp_cnt = 0; 936 937 if (wlan_vdev_mlme_get_opmode(curr_vdev) == QDF_SAP_MODE && 938 QDF_IS_STATUS_ERROR(wlan_mlo_peer_is_assoc_done(ml_peer))) { 939 mlo_err("ML peer " QDF_MAC_ADDR_FMT " is not associated", 940 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 941 return QDF_STATUS_E_INVAL; 942 } 943 944 *new_hw_link_id = INVALID_HW_LINK_ID; 945 current_primary_link_id = 946 wlan_mlo_peer_get_primary_peer_link_id_by_ml_peer(ml_peer); 947 if (current_primary_link_id == WLAN_LINK_ID_INVALID) { 948 mlo_err("ML peer " QDF_MAC_ADDR_FMT "current primary link id is invalid", 949 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 950 return QDF_STATUS_E_INVAL; 951 } 952 953 if (current_primary_link_id == new_primary_link_id) { 954 mlo_err("current and requested link_id are same"); 955 return QDF_STATUS_E_INVAL; 956 } 957 958 if (new_primary_link_id != WLAN_LINK_ID_INVALID) { 959 link_vdev = mlo_get_vdev_by_link_id(curr_vdev, 960 new_primary_link_id); 961 if (!link_vdev) { 962 mlo_err("links vdev not found for link id %d", 963 new_primary_link_id); 964 return QDF_STATUS_E_INVAL; 965 } 966 967 if (wlan_vdev_read_skip_pumac_cnt(link_vdev) > 0) { 968 mlo_err("Selected new ptqm link not allowed for migration"); 969 mlo_release_vdev_ref(link_vdev); 970 return QDF_STATUS_E_PERM; 971 } 972 mlo_release_vdev_ref(link_vdev); 973 } 974 975 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 976 peer_entry = &ml_peer->peer_list[i]; 977 if (!peer_entry || !peer_entry->link_peer) 978 continue; 979 980 if (wlan_peer_get_peer_type(peer_entry->link_peer) == 981 WLAN_PEER_MLO_BRIDGE) 982 goto exit; 983 984 psoc_ids[j++] = wlan_vdev_get_psoc_id( 985 wlan_peer_get_vdev(peer_entry->link_peer)); 986 } 987 988 /* For some 3 link RDPs, there is restriction on primary umac */ 989 if (j == 3) { 990 if (mlo_get_central_umac_id(psoc_ids) != -1) { 991 mlo_err("ML peer " QDF_MAC_ADDR_FMT "migration not supported", 992 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 993 goto exit; 994 } 995 } 996 997 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 998 peer_entry = &ml_peer->peer_list[i]; 999 if (!peer_entry || !peer_entry->link_peer) 1000 continue; 1001 1002 tmp_vdev = wlan_peer_get_vdev(peer_entry->link_peer); 1003 if (!tmp_vdev || tmp_vdev == curr_vdev) 1004 continue; 1005 1006 status = wlan_objmgr_vdev_try_get_ref(tmp_vdev, 1007 WLAN_MLME_SB_ID); 1008 if (QDF_IS_STATUS_ERROR(status)) { 1009 mlo_err("failed to get vdev ref"); 1010 continue; 1011 } 1012 1013 if (wlan_vdev_read_skip_pumac_cnt(tmp_vdev) > 0) { 1014 mlo_debug("Vdev not allowed for migration, skip this vdev"); 1015 wlan_objmgr_vdev_release_ref(tmp_vdev, 1016 WLAN_MLME_SB_ID); 1017 continue; 1018 } 1019 1020 /* Store vdevs which cannot be selected as primary in a temp 1021 * list. force_mig flag will be used to allow migration to vdevs 1022 * which are not allowed to be selected as primary by using the 1023 * primary_umac_skip ini config. This will be helpful in scenarios 1024 * where if the current primary link is going down and peer ptqm 1025 * needs to be migrated but the partner links ofthat mld are 1026 * the user disabled links for ptqm. 1027 */ 1028 if (wlan_vdev_skip_pumac(tmp_vdev)) { 1029 mlo_debug("Vdev cannot be selected as primary"); 1030 tmp_vdev_list[tmp_cnt++] = tmp_vdev; 1031 continue; 1032 } 1033 wlan_vdev_list[idx++] = tmp_vdev; 1034 } 1035 1036 if (new_primary_link_id == WLAN_LINK_ID_INVALID) { 1037 mlo_debug("Invalid link id provided, select new link id"); 1038 /* If there are no vdevs present in wlan_vdev_list, means none 1039 * of the partner vdevs of current MLD are eligible to become 1040 * primary umac. In that case if user has requested force 1041 * migration and there are some vdevs present in temp_vdev_list, 1042 * select new primary umac from those vdev. If no vdevs are 1043 * prenset in any of the list, return failure. 1044 */ 1045 if (idx == 0) { 1046 if (!force_mig || tmp_cnt == 0) { 1047 mlo_err("No link available to be selected as primary"); 1048 goto exit; 1049 } else { 1050 ml_peer->migrate_primary_umac_psoc_id = 1051 wlan_mld_get_best_primary_umac_w_rssi( 1052 ml_peer, 1053 tmp_vdev_list, 1054 true); 1055 if (ml_peer->migrate_primary_umac_psoc_id == 1056 ML_PRIMARY_UMAC_ID_INVAL) { 1057 mlo_err("Unable to fetch new primary link id for ml peer " QDF_MAC_ADDR_FMT, 1058 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1059 goto exit; 1060 } 1061 1062 for (i = 0; i < tmp_cnt; i++) { 1063 if (ml_peer->migrate_primary_umac_psoc_id == 1064 wlan_vdev_get_psoc_id(tmp_vdev_list[i])) { 1065 *new_hw_link_id = wlan_mlo_get_pdev_hw_link_id( 1066 wlan_vdev_get_pdev(tmp_vdev_list[i])); 1067 break; 1068 } 1069 } 1070 } 1071 } else { 1072 ml_peer->migrate_primary_umac_psoc_id = 1073 wlan_mld_get_best_primary_umac_w_rssi( 1074 ml_peer, 1075 wlan_vdev_list, 1076 false); 1077 if (ml_peer->migrate_primary_umac_psoc_id == 1078 ML_PRIMARY_UMAC_ID_INVAL) { 1079 mlo_err("Unable to fetch new primary link id for ml peer " QDF_MAC_ADDR_FMT, 1080 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1081 goto exit; 1082 } 1083 for (i = 0; i < idx; i++) { 1084 if (ml_peer->migrate_primary_umac_psoc_id == 1085 wlan_vdev_get_psoc_id(wlan_vdev_list[i])) { 1086 *new_hw_link_id = wlan_mlo_get_pdev_hw_link_id( 1087 wlan_vdev_get_pdev(wlan_vdev_list[i])); 1088 break; 1089 } 1090 } 1091 } 1092 } else { 1093 /* check if provided link id is part of current ml peer links */ 1094 for (i = 0; i < idx; i++) { 1095 if (new_primary_link_id == wlan_vdev_get_link_id(wlan_vdev_list[i])) { 1096 *new_hw_link_id = wlan_mlo_get_pdev_hw_link_id( 1097 wlan_vdev_get_pdev(wlan_vdev_list[i])); 1098 ml_peer->migrate_primary_umac_psoc_id = 1099 wlan_vdev_get_psoc_id(wlan_vdev_list[i]); 1100 break; 1101 } 1102 } 1103 if (*new_hw_link_id == INVALID_HW_LINK_ID && force_mig) { 1104 for (i = 0; i < tmp_cnt; i++) { 1105 if (new_primary_link_id == 1106 wlan_vdev_get_link_id(tmp_vdev_list[i])) { 1107 *new_hw_link_id = wlan_mlo_get_pdev_hw_link_id( 1108 wlan_vdev_get_pdev(tmp_vdev_list[i])); 1109 ml_peer->migrate_primary_umac_psoc_id = 1110 wlan_vdev_get_psoc_id(tmp_vdev_list[i]); 1111 break; 1112 } 1113 } 1114 } 1115 } 1116 1117 if (*new_hw_link_id == INVALID_HW_LINK_ID) { 1118 mlo_err("New primary link id not found for ml peer " QDF_MAC_ADDR_FMT, 1119 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1120 goto exit; 1121 } 1122 1123 for (i = 0; i < idx; i++) 1124 wlan_objmgr_vdev_release_ref(wlan_vdev_list[i], 1125 WLAN_MLME_SB_ID); 1126 1127 for (i = 0; i < tmp_cnt; i++) 1128 wlan_objmgr_vdev_release_ref(tmp_vdev_list[i], 1129 WLAN_MLME_SB_ID); 1130 return QDF_STATUS_SUCCESS; 1131 1132 exit: 1133 ml_peer->migrate_primary_umac_psoc_id = ML_PRIMARY_UMAC_ID_INVAL; 1134 1135 for (i = 0; i < idx; i++) 1136 wlan_objmgr_vdev_release_ref(wlan_vdev_list[i], 1137 WLAN_MLME_SB_ID); 1138 1139 for (i = 0; i < tmp_cnt; i++) 1140 wlan_objmgr_vdev_release_ref(tmp_vdev_list[i], 1141 WLAN_MLME_SB_ID); 1142 return QDF_STATUS_E_FAILURE; 1143 } 1144 1145 /** 1146 * wlan_mlo_free_ptqm_migrate_list() - API to free peer ptqm migration list 1147 * @list: peer ptqm migration list 1148 * 1149 * API to free peer ptqm migration list 1150 * 1151 * Return: void 1152 */ 1153 static void wlan_mlo_free_ptqm_migrate_list( 1154 struct peer_migrate_ptqm_multi_entries *list) 1155 { 1156 struct peer_ptqm_migrate_list_entry *peer_entry, *next_entry; 1157 1158 peer_entry = mlo_ptqm_list_peek_head(&list->peer_list); 1159 while (peer_entry) { 1160 list->num_entries--; 1161 next_entry = mlo_get_next_peer_ctx(&list->peer_list, 1162 peer_entry); 1163 if (peer_entry->peer) 1164 wlan_objmgr_peer_release_ref(peer_entry->peer, 1165 WLAN_MLME_SB_ID); 1166 qdf_list_remove_node(&list->peer_list, &peer_entry->node); 1167 qdf_mem_free(peer_entry); 1168 peer_entry = next_entry; 1169 } 1170 qdf_list_destroy(&list->peer_list); 1171 } 1172 1173 /** 1174 * wlan_mlo_reset_ptqm_migrate_list() - API to reset peer ptqm migration list 1175 * @ml_dev: MLO dev context 1176 * @list: peer ptqm migration list 1177 * @num_peers_failed: number of peers for which wmi cmd is failed. 1178 * 1179 * API to reset peer ptqm migration list 1180 * 1181 * Return: void 1182 */ 1183 static void wlan_mlo_reset_ptqm_migrate_list( 1184 struct wlan_mlo_dev_context *ml_dev, 1185 struct peer_migrate_ptqm_multi_entries *list, 1186 uint16_t num_peers_failed) 1187 { 1188 struct peer_ptqm_migrate_list_entry *peer_entry, *next_entry; 1189 uint16_t count = 0; 1190 1191 if (!ml_dev) 1192 return; 1193 1194 peer_entry = mlo_ptqm_list_peek_head(&list->peer_list); 1195 while (peer_entry) { 1196 /* Reset the flags only for entries for which wmi 1197 * command trigger is failed 1198 */ 1199 if (count < list->num_entries - num_peers_failed) { 1200 count++; 1201 next_entry = mlo_get_next_peer_ctx(&list->peer_list, 1202 peer_entry); 1203 peer_entry = next_entry; 1204 continue; 1205 } 1206 if (peer_entry->peer) { 1207 qdf_clear_bit(peer_entry->mlo_peer_id, ml_dev->mlo_peer_id_bmap); 1208 peer_entry->peer->mlo_peer_ctx->primary_umac_migration_in_progress = false; 1209 peer_entry->peer->mlo_peer_ctx->migrate_primary_umac_psoc_id = 1210 ML_PRIMARY_UMAC_ID_INVAL; 1211 } 1212 next_entry = mlo_get_next_peer_ctx(&list->peer_list, 1213 peer_entry); 1214 peer_entry = next_entry; 1215 } 1216 } 1217 1218 /** 1219 * wlan_mlo_build_ptqm_migrate_list() - API to build peer ptqm migration list 1220 * @vdev: objmgr vdev list 1221 * @object: peer object 1222 * @arg: list pointer 1223 * 1224 * API to build peer ptqm migration list 1225 * 1226 * Return: void 1227 */ 1228 static void wlan_mlo_build_ptqm_migrate_list(struct wlan_objmgr_vdev *vdev, 1229 void *object, void *arg) 1230 { 1231 struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)object; 1232 struct peer_migrate_ptqm_multi_entries *list = 1233 (struct peer_migrate_ptqm_multi_entries *)arg; 1234 struct peer_ptqm_migrate_list_entry *peer_entry; 1235 struct wlan_mlo_peer_context *ml_peer; 1236 uint16_t new_hw_link_id = INVALID_HW_LINK_ID; 1237 uint8_t current_primary_link_id = WLAN_LINK_ID_INVALID; 1238 QDF_STATUS status; 1239 1240 if (!wlan_peer_is_mlo(peer) || !peer->mlo_peer_ctx) 1241 return; 1242 1243 ml_peer = peer->mlo_peer_ctx; 1244 1245 if (ml_peer->link_peer_cnt == 1) 1246 return; 1247 1248 if (ml_peer->primary_umac_migration_in_progress) { 1249 mlo_err("peer " QDF_MAC_ADDR_FMT " primary umac migration already in progress", 1250 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1251 return; 1252 } 1253 1254 current_primary_link_id = wlan_mlo_peer_get_primary_peer_link_id_by_ml_peer(ml_peer); 1255 if (current_primary_link_id == WLAN_LINK_ID_INVALID || 1256 current_primary_link_id != wlan_vdev_get_link_id(vdev)) { 1257 mlo_debug("peer " QDF_MAC_ADDR_FMT " not having primary on current vdev", 1258 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1259 return; 1260 } 1261 1262 status = wlan_mlo_get_new_ptqm_id(vdev, ml_peer, 1263 WLAN_LINK_ID_INVALID, 1264 &new_hw_link_id, true); 1265 if (QDF_IS_STATUS_ERROR(status)) { 1266 mlo_err("peer " QDF_MAC_ADDR_FMT " unable to get new ptqm id", 1267 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1268 return; 1269 } 1270 ml_peer->primary_umac_migration_in_progress = true; 1271 1272 peer_entry = (struct peer_ptqm_migrate_list_entry *) 1273 qdf_mem_malloc(sizeof(struct peer_ptqm_migrate_list_entry)); 1274 if (!peer_entry) { 1275 mlo_err("peer " QDF_MAC_ADDR_FMT " unable to allocate peer entry", 1276 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1277 return; 1278 } 1279 1280 status = wlan_objmgr_peer_try_get_ref(peer, WLAN_MLME_SB_ID); 1281 peer_entry->peer = peer; 1282 peer_entry->new_hw_link_id = new_hw_link_id; 1283 peer_entry->mlo_peer_id = ml_peer->mlo_peer_id; 1284 qdf_list_insert_back(&list->peer_list, &peer_entry->node); 1285 list->num_entries++; 1286 } 1287 1288 /** 1289 * wlan_mlo_trigger_link_ptqm_migration() - API to trigger ptqm migration 1290 * for a link 1291 * @vdev: objmgr vdev object 1292 * 1293 * API to trigger ptqm migration of all peers having primary on given link 1294 * 1295 * Return: QDF_STATUS 1296 */ 1297 static QDF_STATUS wlan_mlo_trigger_link_ptqm_migration( 1298 struct wlan_objmgr_vdev *vdev) 1299 { 1300 struct peer_migrate_ptqm_multi_entries migrate_list = {0}; 1301 QDF_STATUS status; 1302 uint16_t num_peers_failed = 0; 1303 1304 qdf_list_create(&migrate_list.peer_list, MAX_MLO_PEER_ID); 1305 wlan_objmgr_iterate_peerobj_list(vdev, 1306 wlan_mlo_build_ptqm_migrate_list, 1307 &migrate_list, WLAN_MLME_NB_ID); 1308 1309 /* trigger WMI */ 1310 if (migrate_list.num_entries == 0) { 1311 mlo_err("No peer found"); 1312 return QDF_STATUS_SUCCESS; 1313 } 1314 1315 status = wlan_mlo_send_ptqm_migrate_cmd(vdev, &migrate_list, 1316 &num_peers_failed); 1317 if (QDF_IS_STATUS_ERROR(status)) 1318 wlan_mlo_reset_ptqm_migrate_list(vdev->mlo_dev_ctx, 1319 &migrate_list, 1320 num_peers_failed); 1321 wlan_mlo_free_ptqm_migrate_list(&migrate_list); 1322 return status; 1323 } 1324 1325 QDF_STATUS wlan_mlo_set_ptqm_migration(struct wlan_objmgr_vdev *vdev, 1326 struct wlan_mlo_peer_context *ml_peer, 1327 bool link_migration, 1328 uint32_t link_id, bool force_mig) 1329 { 1330 uint16_t new_hw_link_id = INVALID_HW_LINK_ID; 1331 struct peer_migrate_ptqm_multi_entries migrate_list = {0}; 1332 struct peer_ptqm_migrate_list_entry *peer_entry; 1333 struct wlan_objmgr_vdev *curr_vdev = NULL; 1334 uint8_t current_primary_link_id = WLAN_LINK_ID_INVALID; 1335 uint16_t num_peers_failed = 0; 1336 QDF_STATUS status; 1337 1338 if (!vdev) { 1339 mlo_err("Vdev is NULL"); 1340 return QDF_STATUS_E_INVAL; 1341 } 1342 1343 if (link_migration == false && !ml_peer) { 1344 mlo_err("ML peer is NULL"); 1345 return QDF_STATUS_E_INVAL; 1346 } 1347 1348 if (link_migration) { 1349 mlo_err("Trigger migration for full link"); 1350 // trigger full link migration 1351 status = wlan_mlo_trigger_link_ptqm_migration(vdev); 1352 if (QDF_IS_STATUS_ERROR(status)) 1353 mlo_err("Failed to trigger link migration"); 1354 return status; 1355 } 1356 1357 if (ml_peer->link_peer_cnt == 1) { 1358 mlo_err("peer " QDF_MAC_ADDR_FMT " is SLO", 1359 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1360 return QDF_STATUS_E_INVAL; 1361 } 1362 1363 if (ml_peer->primary_umac_migration_in_progress) { 1364 mlo_err("peer " QDF_MAC_ADDR_FMT " primary umac migration already in progress", 1365 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1366 return QDF_STATUS_E_INVAL; 1367 } 1368 1369 current_primary_link_id = wlan_mlo_peer_get_primary_peer_link_id_by_ml_peer(ml_peer); 1370 if (current_primary_link_id == WLAN_LINK_ID_INVALID) { 1371 mlo_err("Current primary link id is invalid"); 1372 return QDF_STATUS_E_INVAL; 1373 } 1374 1375 curr_vdev = mlo_get_vdev_by_link_id(vdev, current_primary_link_id); 1376 if (!curr_vdev) { 1377 mlo_err("Unable to get current primary vdev"); 1378 return QDF_STATUS_E_INVAL; 1379 } 1380 1381 status = wlan_mlo_get_new_ptqm_id(curr_vdev, ml_peer, 1382 link_id, &new_hw_link_id, force_mig); 1383 if (QDF_IS_STATUS_ERROR(status)) { 1384 mlo_err("peer " QDF_MAC_ADDR_FMT " unable to get new ptqm id", 1385 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 1386 goto exit; 1387 } 1388 ml_peer->primary_umac_migration_in_progress = true; 1389 1390 peer_entry = (struct peer_ptqm_migrate_list_entry *) 1391 qdf_mem_malloc(sizeof(struct peer_ptqm_migrate_list_entry)); 1392 if (!peer_entry) { 1393 mlo_err("Failed to allocate peer entry"); 1394 goto exit; 1395 } 1396 1397 peer_entry->new_hw_link_id = new_hw_link_id; 1398 peer_entry->mlo_peer_id = ml_peer->mlo_peer_id; 1399 qdf_list_create(&migrate_list.peer_list, MAX_MLO_PEER_ID); 1400 qdf_list_insert_back(&migrate_list.peer_list, &peer_entry->node); 1401 migrate_list.num_entries = 1; 1402 1403 //trigger WMI 1404 status = wlan_mlo_send_ptqm_migrate_cmd(curr_vdev, &migrate_list, 1405 &num_peers_failed); 1406 if (QDF_IS_STATUS_ERROR(status)) 1407 wlan_mlo_reset_ptqm_migrate_list(curr_vdev->mlo_dev_ctx, 1408 &migrate_list, 1409 num_peers_failed); 1410 wlan_mlo_free_ptqm_migrate_list(&migrate_list); 1411 1412 mlo_release_vdev_ref(curr_vdev); 1413 1414 return status; 1415 1416 exit: 1417 if (curr_vdev) 1418 mlo_release_vdev_ref(curr_vdev); 1419 1420 return QDF_STATUS_E_FAILURE; 1421 } 1422 #endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ 1423