xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c (revision f3fcb9b56ef41dfe15c1ffbe6562d58a0c5525c2)
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, &param);
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