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