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