xref: /wlan-driver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for any
5*5113495bSYour Name  * purpose with or without fee is hereby granted, provided that the above
6*5113495bSYour Name  * copyright notice and this permission notice appear in all copies.
7*5113495bSYour Name  *
8*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*5113495bSYour Name  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*5113495bSYour Name  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*5113495bSYour Name  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*5113495bSYour Name  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*5113495bSYour Name  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*5113495bSYour Name  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*5113495bSYour Name  */
16*5113495bSYour Name 
17*5113495bSYour Name /*
18*5113495bSYour Name  * DOC: contains MLO manager Link Switch related functionality
19*5113495bSYour Name  */
20*5113495bSYour Name #include <wlan_mlo_mgr_link_switch.h>
21*5113495bSYour Name #include <wlan_mlo_mgr_main.h>
22*5113495bSYour Name #include <wlan_mlo_mgr_sta.h>
23*5113495bSYour Name #include <wlan_serialization_api.h>
24*5113495bSYour Name #include <wlan_cm_api.h>
25*5113495bSYour Name #include <wlan_crypto_def_i.h>
26*5113495bSYour Name #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
27*5113495bSYour Name #include "wlan_cm_roam_api.h"
28*5113495bSYour Name #include <wlan_mlo_mgr_roam.h>
29*5113495bSYour Name #endif
30*5113495bSYour Name #include "host_diag_core_event.h"
31*5113495bSYour Name 
mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_mac_update * ml_mac_update)32*5113495bSYour Name void mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev *vdev,
33*5113495bSYour Name 				       struct wlan_mlo_link_mac_update *ml_mac_update)
34*5113495bSYour Name {
35*5113495bSYour Name 	struct mlo_link_info *link_info;
36*5113495bSYour Name 	uint8_t link_info_iter;
37*5113495bSYour Name 	struct mlo_vdev_link_mac_info *link_mac_info;
38*5113495bSYour Name 
39*5113495bSYour Name 	if (!vdev || !vdev->mlo_dev_ctx || !ml_mac_update)
40*5113495bSYour Name 		return;
41*5113495bSYour Name 
42*5113495bSYour Name 	link_mac_info = &ml_mac_update->link_mac_info[0];
43*5113495bSYour Name 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
44*5113495bSYour Name 
45*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
46*5113495bSYour Name 	     link_info_iter++) {
47*5113495bSYour Name 		qdf_mem_copy(&link_info->link_addr,
48*5113495bSYour Name 			     &link_mac_info->link_mac_addr,
49*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
50*5113495bSYour Name 
51*5113495bSYour Name 		link_info->vdev_id = link_mac_info->vdev_id;
52*5113495bSYour Name 		mlo_debug("Update STA Link info for vdev_id %d, link_addr:" QDF_MAC_ADDR_FMT,
53*5113495bSYour Name 			  link_info->vdev_id,
54*5113495bSYour Name 			  QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
55*5113495bSYour Name 		link_mac_info++;
56*5113495bSYour Name 		link_info++;
57*5113495bSYour Name 	}
58*5113495bSYour Name }
59*5113495bSYour Name 
mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev * vdev,uint8_t link_id,uint8_t * ap_link_addr,struct wlan_channel channel)60*5113495bSYour Name void mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id,
61*5113495bSYour Name 				 uint8_t *ap_link_addr,
62*5113495bSYour Name 				 struct wlan_channel channel)
63*5113495bSYour Name {
64*5113495bSYour Name 	struct mlo_link_info *link_info;
65*5113495bSYour Name 	uint8_t link_info_iter;
66*5113495bSYour Name 
67*5113495bSYour Name 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
68*5113495bSYour Name 		return;
69*5113495bSYour Name 
70*5113495bSYour Name 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
71*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
72*5113495bSYour Name 	     link_info_iter++) {
73*5113495bSYour Name 		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
74*5113495bSYour Name 			break;
75*5113495bSYour Name 
76*5113495bSYour Name 		link_info++;
77*5113495bSYour Name 	}
78*5113495bSYour Name 
79*5113495bSYour Name 	if (link_info_iter == WLAN_MAX_ML_BSS_LINKS)
80*5113495bSYour Name 		return;
81*5113495bSYour Name 
82*5113495bSYour Name 	qdf_mem_copy(&link_info->ap_link_addr, ap_link_addr, QDF_MAC_ADDR_SIZE);
83*5113495bSYour Name 
84*5113495bSYour Name 	qdf_mem_copy(link_info->link_chan_info, &channel, sizeof(channel));
85*5113495bSYour Name 	link_info->link_status_flags = 0;
86*5113495bSYour Name 	link_info->link_id = link_id;
87*5113495bSYour Name 	link_info->is_link_active = false;
88*5113495bSYour Name 
89*5113495bSYour Name 	mlo_debug("Update AP Link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
90*5113495bSYour Name 		  link_info->link_id, link_info->vdev_id,
91*5113495bSYour Name 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
92*5113495bSYour Name }
93*5113495bSYour Name 
mlo_mgr_clear_ap_link_info(struct wlan_objmgr_vdev * vdev,uint8_t * ap_link_addr)94*5113495bSYour Name void mlo_mgr_clear_ap_link_info(struct wlan_objmgr_vdev *vdev,
95*5113495bSYour Name 				uint8_t *ap_link_addr)
96*5113495bSYour Name {
97*5113495bSYour Name 	struct mlo_link_info *link_info;
98*5113495bSYour Name 	uint8_t link_info_iter;
99*5113495bSYour Name 
100*5113495bSYour Name 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
101*5113495bSYour Name 		return;
102*5113495bSYour Name 
103*5113495bSYour Name 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
104*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
105*5113495bSYour Name 	     link_info_iter++) {
106*5113495bSYour Name 		if (qdf_is_macaddr_equal(&link_info->ap_link_addr,
107*5113495bSYour Name 					 (struct qdf_mac_addr *)ap_link_addr)) {
108*5113495bSYour Name 			mlo_debug("Clear AP link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
109*5113495bSYour Name 				  link_info->link_id, link_info->vdev_id,
110*5113495bSYour Name 				  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
111*5113495bSYour Name 
112*5113495bSYour Name 			qdf_mem_zero(&link_info->ap_link_addr,
113*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
114*5113495bSYour Name 			qdf_mem_zero(link_info->link_chan_info,
115*5113495bSYour Name 				     sizeof(*link_info->link_chan_info));
116*5113495bSYour Name 			link_info->link_id = WLAN_INVALID_LINK_ID;
117*5113495bSYour Name 			link_info->link_status_flags = 0;
118*5113495bSYour Name 
119*5113495bSYour Name 			return;
120*5113495bSYour Name 		}
121*5113495bSYour Name 
122*5113495bSYour Name 		link_info++;
123*5113495bSYour Name 	}
124*5113495bSYour Name }
125*5113495bSYour Name 
mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev * vdev,uint8_t link_id,uint8_t * ap_link_addr,struct wlan_channel channel)126*5113495bSYour Name void mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id,
127*5113495bSYour Name 				    uint8_t *ap_link_addr,
128*5113495bSYour Name 				    struct wlan_channel channel)
129*5113495bSYour Name {
130*5113495bSYour Name 	struct mlo_link_info *link_info;
131*5113495bSYour Name 
132*5113495bSYour Name 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
133*5113495bSYour Name 		return;
134*5113495bSYour Name 
135*5113495bSYour Name 	link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id);
136*5113495bSYour Name 	if (!link_info)
137*5113495bSYour Name 		return;
138*5113495bSYour Name 
139*5113495bSYour Name 	qdf_mem_copy(link_info->link_chan_info, &channel,
140*5113495bSYour Name 		     sizeof(*link_info->link_chan_info));
141*5113495bSYour Name 
142*5113495bSYour Name 	mlo_debug("update AP channel info link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
143*5113495bSYour Name 		  link_info->link_id, link_info->vdev_id,
144*5113495bSYour Name 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
145*5113495bSYour Name 	mlo_debug("ch_freq: %d, freq1: %d, freq2: %d, phy_mode: %d",
146*5113495bSYour Name 		  link_info->link_chan_info->ch_freq,
147*5113495bSYour Name 		  link_info->link_chan_info->ch_cfreq1,
148*5113495bSYour Name 		  link_info->link_chan_info->ch_cfreq2,
149*5113495bSYour Name 		  link_info->link_chan_info->ch_phymode);
150*5113495bSYour Name }
151*5113495bSYour Name 
mlo_mgr_update_link_info_reset(struct wlan_objmgr_psoc * psoc,struct wlan_mlo_dev_context * ml_dev)152*5113495bSYour Name void mlo_mgr_update_link_info_reset(struct wlan_objmgr_psoc *psoc,
153*5113495bSYour Name 				    struct wlan_mlo_dev_context *ml_dev)
154*5113495bSYour Name {
155*5113495bSYour Name 	struct mlo_link_info *link_info;
156*5113495bSYour Name 	uint8_t link_info_iter;
157*5113495bSYour Name 
158*5113495bSYour Name 	if (!ml_dev)
159*5113495bSYour Name 		return;
160*5113495bSYour Name 
161*5113495bSYour Name 	link_info = &ml_dev->link_ctx->links_info[0];
162*5113495bSYour Name 
163*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
164*5113495bSYour Name 	     link_info_iter++) {
165*5113495bSYour Name 		if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) &&
166*5113495bSYour Name 		    !qdf_is_macaddr_zero(&link_info->link_addr))
167*5113495bSYour Name 			wlan_crypto_free_key_by_link_id(
168*5113495bSYour Name 						psoc,
169*5113495bSYour Name 						&link_info->link_addr,
170*5113495bSYour Name 						link_info->link_id);
171*5113495bSYour Name 		qdf_mem_zero(&link_info->link_addr, QDF_MAC_ADDR_SIZE);
172*5113495bSYour Name 		qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE);
173*5113495bSYour Name 		qdf_mem_zero(link_info->link_chan_info,
174*5113495bSYour Name 			     sizeof(*link_info->link_chan_info));
175*5113495bSYour Name 		link_info->vdev_id = WLAN_INVALID_VDEV_ID;
176*5113495bSYour Name 		link_info->link_id = WLAN_INVALID_LINK_ID;
177*5113495bSYour Name 		link_info->link_status_flags = 0;
178*5113495bSYour Name 		link_info++;
179*5113495bSYour Name 	}
180*5113495bSYour Name }
181*5113495bSYour Name 
mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev * vdev)182*5113495bSYour Name void mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev *vdev)
183*5113495bSYour Name {
184*5113495bSYour Name 	struct mlo_link_info *link_info;
185*5113495bSYour Name 	uint8_t link_info_iter;
186*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
187*5113495bSYour Name 
188*5113495bSYour Name 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx)
189*5113495bSYour Name 		return;
190*5113495bSYour Name 
191*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
192*5113495bSYour Name 	if (!psoc) {
193*5113495bSYour Name 		mlo_err("psoc NULL");
194*5113495bSYour Name 		return;
195*5113495bSYour Name 	}
196*5113495bSYour Name 
197*5113495bSYour Name 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
198*5113495bSYour Name 
199*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
200*5113495bSYour Name 	     link_info_iter++) {
201*5113495bSYour Name 		if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) &&
202*5113495bSYour Name 		    !qdf_is_macaddr_zero(&link_info->link_addr))
203*5113495bSYour Name 			wlan_crypto_free_key_by_link_id(
204*5113495bSYour Name 						psoc,
205*5113495bSYour Name 						&link_info->link_addr,
206*5113495bSYour Name 						link_info->link_id);
207*5113495bSYour Name 		qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE);
208*5113495bSYour Name 		qdf_mem_zero(link_info->link_chan_info,
209*5113495bSYour Name 			     sizeof(*link_info->link_chan_info));
210*5113495bSYour Name 		link_info->link_id = WLAN_INVALID_LINK_ID;
211*5113495bSYour Name 		link_info->link_status_flags = 0;
212*5113495bSYour Name 		link_info++;
213*5113495bSYour Name 	}
214*5113495bSYour Name }
215*5113495bSYour Name 
216*5113495bSYour Name struct mlo_link_info
mlo_mgr_get_ap_link(struct wlan_objmgr_vdev * vdev)217*5113495bSYour Name *mlo_mgr_get_ap_link(struct wlan_objmgr_vdev *vdev)
218*5113495bSYour Name {
219*5113495bSYour Name 	if (!vdev || !vdev->mlo_dev_ctx)
220*5113495bSYour Name 		return NULL;
221*5113495bSYour Name 
222*5113495bSYour Name 	return &vdev->mlo_dev_ctx->link_ctx->links_info[0];
223*5113495bSYour Name }
224*5113495bSYour Name 
225*5113495bSYour Name static
mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context * ml_dev)226*5113495bSYour Name void mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
227*5113495bSYour Name {
228*5113495bSYour Name 	struct mlo_link_info *link_info;
229*5113495bSYour Name 	uint8_t link_info_iter;
230*5113495bSYour Name 
231*5113495bSYour Name 	if (!ml_dev)
232*5113495bSYour Name 		return;
233*5113495bSYour Name 
234*5113495bSYour Name 	link_info = &ml_dev->link_ctx->links_info[0];
235*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
236*5113495bSYour Name 	     link_info_iter++) {
237*5113495bSYour Name 		link_info->link_chan_info =
238*5113495bSYour Name 			qdf_mem_malloc(sizeof(*link_info->link_chan_info));
239*5113495bSYour Name 		if (!link_info->link_chan_info)
240*5113495bSYour Name 			return;
241*5113495bSYour Name 		link_info++;
242*5113495bSYour Name 	}
243*5113495bSYour Name }
244*5113495bSYour Name 
245*5113495bSYour Name static
mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context * ml_dev)246*5113495bSYour Name void mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
247*5113495bSYour Name {
248*5113495bSYour Name 	struct mlo_link_info *link_info;
249*5113495bSYour Name 	uint8_t link_info_iter;
250*5113495bSYour Name 
251*5113495bSYour Name 	if (!ml_dev)
252*5113495bSYour Name 		return;
253*5113495bSYour Name 
254*5113495bSYour Name 	link_info = &ml_dev->link_ctx->links_info[0];
255*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
256*5113495bSYour Name 	     link_info_iter++) {
257*5113495bSYour Name 		if (link_info->link_chan_info)
258*5113495bSYour Name 			qdf_mem_free(link_info->link_chan_info);
259*5113495bSYour Name 		link_info++;
260*5113495bSYour Name 	}
261*5113495bSYour Name }
262*5113495bSYour Name 
263*5113495bSYour Name #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
264*5113495bSYour Name struct mlo_link_info
mlo_mgr_get_ap_link_by_link_id(struct wlan_mlo_dev_context * mlo_dev_ctx,int link_id)265*5113495bSYour Name *mlo_mgr_get_ap_link_by_link_id(struct wlan_mlo_dev_context *mlo_dev_ctx,
266*5113495bSYour Name 				int link_id)
267*5113495bSYour Name {
268*5113495bSYour Name 	struct mlo_link_info *link_info;
269*5113495bSYour Name 	uint8_t link_info_iter;
270*5113495bSYour Name 
271*5113495bSYour Name 	if (!mlo_dev_ctx || link_id < 0 || link_id > 15)
272*5113495bSYour Name 		return NULL;
273*5113495bSYour Name 
274*5113495bSYour Name 	link_info = &mlo_dev_ctx->link_ctx->links_info[0];
275*5113495bSYour Name 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
276*5113495bSYour Name 	     link_info_iter++) {
277*5113495bSYour Name 		if (link_info->link_id == link_id)
278*5113495bSYour Name 			return link_info;
279*5113495bSYour Name 		link_info++;
280*5113495bSYour Name 	}
281*5113495bSYour Name 
282*5113495bSYour Name 	return NULL;
283*5113495bSYour Name }
284*5113495bSYour Name 
mlo_mgr_update_csa_link_info(struct wlan_objmgr_pdev * pdev,struct wlan_mlo_dev_context * mlo_dev_ctx,struct csa_offload_params * csa_param,uint8_t link_id)285*5113495bSYour Name bool mlo_mgr_update_csa_link_info(struct wlan_objmgr_pdev *pdev,
286*5113495bSYour Name 				  struct wlan_mlo_dev_context *mlo_dev_ctx,
287*5113495bSYour Name 				  struct csa_offload_params *csa_param,
288*5113495bSYour Name 				  uint8_t link_id)
289*5113495bSYour Name {
290*5113495bSYour Name 	struct mlo_link_info *link_info;
291*5113495bSYour Name 	uint16_t bw_val;
292*5113495bSYour Name 	uint32_t ch_cfreq1, ch_cfreq2;
293*5113495bSYour Name 
294*5113495bSYour Name 	if (!mlo_dev_ctx) {
295*5113495bSYour Name 		mlo_err("invalid mlo dev ctx");
296*5113495bSYour Name 		goto done;
297*5113495bSYour Name 	}
298*5113495bSYour Name 
299*5113495bSYour Name 	bw_val = wlan_reg_get_bw_value(csa_param->new_ch_width);
300*5113495bSYour Name 
301*5113495bSYour Name 	link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id);
302*5113495bSYour Name 	if (!link_info) {
303*5113495bSYour Name 		mlo_err("invalid link_info");
304*5113495bSYour Name 		goto done;
305*5113495bSYour Name 	}
306*5113495bSYour Name 
307*5113495bSYour Name 	link_info->link_chan_info->ch_freq = csa_param->csa_chan_freq;
308*5113495bSYour Name 
309*5113495bSYour Name 	if (wlan_reg_is_6ghz_chan_freq(csa_param->csa_chan_freq)) {
310*5113495bSYour Name 		ch_cfreq1 = wlan_reg_compute_6g_center_freq_from_cfi(
311*5113495bSYour Name 					csa_param->new_ch_freq_seg1);
312*5113495bSYour Name 		ch_cfreq2 = wlan_reg_compute_6g_center_freq_from_cfi(
313*5113495bSYour Name 					csa_param->new_ch_freq_seg2);
314*5113495bSYour Name 	} else {
315*5113495bSYour Name 		ch_cfreq1 = wlan_reg_legacy_chan_to_freq(pdev,
316*5113495bSYour Name 					csa_param->new_ch_freq_seg1);
317*5113495bSYour Name 		ch_cfreq2 = wlan_reg_legacy_chan_to_freq(pdev,
318*5113495bSYour Name 					csa_param->new_ch_freq_seg2);
319*5113495bSYour Name 	}
320*5113495bSYour Name 
321*5113495bSYour Name 	link_info->link_chan_info->ch_cfreq1 = ch_cfreq1;
322*5113495bSYour Name 	link_info->link_chan_info->ch_cfreq2 = ch_cfreq2;
323*5113495bSYour Name 
324*5113495bSYour Name 	link_info->link_chan_info->ch_phymode = wlan_eht_chan_phy_mode(
325*5113495bSYour Name 					csa_param->csa_chan_freq,
326*5113495bSYour Name 					bw_val, csa_param->new_ch_width);
327*5113495bSYour Name 
328*5113495bSYour Name 	mlo_debug("CSA: freq: %d, cfreq1: %d, cfreq2: %d, bw: %d, phymode:%d",
329*5113495bSYour Name 		  link_info->link_chan_info->ch_freq, ch_cfreq1, ch_cfreq2,
330*5113495bSYour Name 		  bw_val, link_info->link_chan_info->ch_phymode);
331*5113495bSYour Name 
332*5113495bSYour Name 	return true;
333*5113495bSYour Name done:
334*5113495bSYour Name 	return false;
335*5113495bSYour Name }
336*5113495bSYour Name 
337*5113495bSYour Name struct wlan_objmgr_vdev *
mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev * vdev)338*5113495bSYour Name mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev *vdev)
339*5113495bSYour Name {
340*5113495bSYour Name 	uint8_t vdev_id;
341*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
342*5113495bSYour Name 	struct wlan_objmgr_vdev *assoc_vdev;
343*5113495bSYour Name 
344*5113495bSYour Name 	if (!vdev)
345*5113495bSYour Name 		return NULL;
346*5113495bSYour Name 
347*5113495bSYour Name 	if (!mlo_mgr_is_link_switch_on_assoc_vdev(vdev))
348*5113495bSYour Name 		return NULL;
349*5113495bSYour Name 
350*5113495bSYour Name 	vdev_id = vdev->mlo_dev_ctx->link_ctx->last_req.vdev_id;
351*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
352*5113495bSYour Name 	if (!psoc) {
353*5113495bSYour Name 		mlo_err("PSOC NULL");
354*5113495bSYour Name 		return NULL;
355*5113495bSYour Name 	}
356*5113495bSYour Name 
357*5113495bSYour Name 	assoc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
358*5113495bSYour Name 							  WLAN_MLO_MGR_ID);
359*5113495bSYour Name 
360*5113495bSYour Name 	return assoc_vdev;
361*5113495bSYour Name }
362*5113495bSYour Name 
mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev * vdev)363*5113495bSYour Name bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
364*5113495bSYour Name {
365*5113495bSYour Name 	enum mlo_link_switch_req_state state;
366*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
367*5113495bSYour Name 
368*5113495bSYour Name 	if (!mlo_dev_ctx)
369*5113495bSYour Name 		return false;
370*5113495bSYour Name 
371*5113495bSYour Name 	state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
372*5113495bSYour Name 	return (state > MLO_LINK_SWITCH_STATE_INIT);
373*5113495bSYour Name }
374*5113495bSYour Name 
mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev * vdev)375*5113495bSYour Name bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev)
376*5113495bSYour Name {
377*5113495bSYour Name 	if (!mlo_mgr_is_link_switch_in_progress(vdev))
378*5113495bSYour Name 		return false;
379*5113495bSYour Name 
380*5113495bSYour Name 	return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag;
381*5113495bSYour Name }
382*5113495bSYour Name 
mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context * mlo_dev_ctx)383*5113495bSYour Name void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
384*5113495bSYour Name {
385*5113495bSYour Name 	mlo_dev_lock_acquire(mlo_dev_ctx);
386*5113495bSYour Name 	mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE;
387*5113495bSYour Name 	mlo_dev_lock_release(mlo_dev_ctx);
388*5113495bSYour Name }
389*5113495bSYour Name 
390*5113495bSYour Name QDF_STATUS
mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context * mlo_dev_ctx)391*5113495bSYour Name mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
392*5113495bSYour Name {
393*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
394*5113495bSYour Name 	enum mlo_link_switch_req_state cur_state, next_state;
395*5113495bSYour Name 
396*5113495bSYour Name 	mlo_dev_lock_acquire(mlo_dev_ctx);
397*5113495bSYour Name 	cur_state = mlo_dev_ctx->link_ctx->last_req.state;
398*5113495bSYour Name 	switch (cur_state) {
399*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_IDLE:
400*5113495bSYour Name 		next_state = MLO_LINK_SWITCH_STATE_INIT;
401*5113495bSYour Name 		break;
402*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_INIT:
403*5113495bSYour Name 		next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK;
404*5113495bSYour Name 		break;
405*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK:
406*5113495bSYour Name 		next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR;
407*5113495bSYour Name 		break;
408*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR:
409*5113495bSYour Name 		next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK;
410*5113495bSYour Name 		break;
411*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK:
412*5113495bSYour Name 		next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS;
413*5113495bSYour Name 		break;
414*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
415*5113495bSYour Name 		next_state = MLO_LINK_SWITCH_STATE_IDLE;
416*5113495bSYour Name 		break;
417*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_ABORT_TRANS:
418*5113495bSYour Name 		next_state = cur_state;
419*5113495bSYour Name 		status = QDF_STATUS_E_PERM;
420*5113495bSYour Name 		mlo_debug("State transition not allowed");
421*5113495bSYour Name 		break;
422*5113495bSYour Name 	default:
423*5113495bSYour Name 		QDF_ASSERT(0);
424*5113495bSYour Name 		break;
425*5113495bSYour Name 	}
426*5113495bSYour Name 	mlo_dev_ctx->link_ctx->last_req.state = next_state;
427*5113495bSYour Name 	mlo_dev_lock_release(mlo_dev_ctx);
428*5113495bSYour Name 
429*5113495bSYour Name 	return status;
430*5113495bSYour Name }
431*5113495bSYour Name 
432*5113495bSYour Name void
mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context * mlo_dev_ctx)433*5113495bSYour Name mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
434*5113495bSYour Name {
435*5113495bSYour Name 	enum mlo_link_switch_req_state next_state =
436*5113495bSYour Name 					MLO_LINK_SWITCH_STATE_ABORT_TRANS;
437*5113495bSYour Name 
438*5113495bSYour Name 	mlo_dev_lock_acquire(mlo_dev_ctx);
439*5113495bSYour Name 	mlo_dev_ctx->link_ctx->last_req.state = next_state;
440*5113495bSYour Name 	mlo_dev_lock_release(mlo_dev_ctx);
441*5113495bSYour Name }
442*5113495bSYour Name 
443*5113495bSYour Name enum mlo_link_switch_req_state
mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context * mlo_dev_ctx)444*5113495bSYour Name mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
445*5113495bSYour Name {
446*5113495bSYour Name 	enum mlo_link_switch_req_state state;
447*5113495bSYour Name 
448*5113495bSYour Name 	mlo_dev_lock_acquire(mlo_dev_ctx);
449*5113495bSYour Name 	state = mlo_dev_ctx->link_ctx->last_req.state;
450*5113495bSYour Name 	mlo_dev_lock_release(mlo_dev_ctx);
451*5113495bSYour Name 
452*5113495bSYour Name 	return state;
453*5113495bSYour Name }
454*5113495bSYour Name 
455*5113495bSYour Name #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
456*5113495bSYour Name static void
mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_vdev * assoc_vdev)457*5113495bSYour Name mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
458*5113495bSYour Name 				       struct wlan_objmgr_vdev *assoc_vdev)
459*5113495bSYour Name {
460*5113495bSYour Name 	QDF_STATUS status;
461*5113495bSYour Name 
462*5113495bSYour Name 	status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
463*5113495bSYour Name 					   wlan_vdev_get_id(assoc_vdev),
464*5113495bSYour Name 					   WLAN_ROAM_DEINIT,
465*5113495bSYour Name 					   REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE);
466*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
467*5113495bSYour Name 		mlo_err("vdev:%d failed to change RSO state to deinit",
468*5113495bSYour Name 			wlan_vdev_get_id(assoc_vdev));
469*5113495bSYour Name }
470*5113495bSYour Name 
471*5113495bSYour Name static void
mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev * vdev)472*5113495bSYour Name mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev *vdev)
473*5113495bSYour Name {
474*5113495bSYour Name 	wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
475*5113495bSYour Name 				  wlan_vdev_get_id(vdev),
476*5113495bSYour Name 				  WLAN_ROAM_RSO_ENABLED,
477*5113495bSYour Name 				  REASON_CONNECT);
478*5113495bSYour Name }
479*5113495bSYour Name #else
480*5113495bSYour Name static inline void
mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_vdev * assoc_vdev)481*5113495bSYour Name mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
482*5113495bSYour Name 				       struct wlan_objmgr_vdev *assoc_vdev)
483*5113495bSYour Name {}
484*5113495bSYour Name 
485*5113495bSYour Name static inline void
mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev * vdev)486*5113495bSYour Name mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev *vdev)
487*5113495bSYour Name {}
488*5113495bSYour Name #endif
489*5113495bSYour Name 
490*5113495bSYour Name static QDF_STATUS
mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * lswitch_req)491*5113495bSYour Name mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev *vdev,
492*5113495bSYour Name 				      struct wlan_mlo_link_switch_req *lswitch_req)
493*5113495bSYour Name {
494*5113495bSYour Name 	uint8_t idx;
495*5113495bSYour Name 	uint16_t vdev_count;
496*5113495bSYour Name 	struct wlan_objmgr_vdev *assoc_vdev;
497*5113495bSYour Name 	struct wlan_mlo_sta *sta_ctx;
498*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
499*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
500*5113495bSYour Name 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
501*5113495bSYour Name 	QDF_STATUS(*cb)(struct wlan_objmgr_vdev *vdev,
502*5113495bSYour Name 			uint8_t non_trans_vdev_id);
503*5113495bSYour Name 
504*5113495bSYour Name 	if (!vdev->mlo_dev_ctx)
505*5113495bSYour Name 		return status;
506*5113495bSYour Name 
507*5113495bSYour Name 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
508*5113495bSYour Name 	if (!sta_ctx)
509*5113495bSYour Name 		return status;
510*5113495bSYour Name 
511*5113495bSYour Name 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
512*5113495bSYour Name 	if (!assoc_vdev)
513*5113495bSYour Name 		return status;
514*5113495bSYour Name 
515*5113495bSYour Name 	cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_link_switch_notification;
516*5113495bSYour Name 
517*5113495bSYour Name 	if (lswitch_req->restore_vdev_flag) {
518*5113495bSYour Name 		wlan_vdev_mlme_clear_mlo_link_vdev(vdev);
519*5113495bSYour Name 		wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev);
520*5113495bSYour Name 		mlo_mgr_reset_roam_state_for_link_vdev(vdev, assoc_vdev);
521*5113495bSYour Name 
522*5113495bSYour Name 		lswitch_req->restore_vdev_flag = false;
523*5113495bSYour Name 
524*5113495bSYour Name 		status = cb(assoc_vdev, wlan_vdev_get_id(vdev));
525*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status))
526*5113495bSYour Name 			mlo_debug("OSIF deflink restore failed");
527*5113495bSYour Name 
528*5113495bSYour Name 		return status;
529*5113495bSYour Name 	}
530*5113495bSYour Name 
531*5113495bSYour Name 	if (wlan_vdev_get_id(assoc_vdev) != lswitch_req->vdev_id) {
532*5113495bSYour Name 		mlo_debug("Not on assoc VDEV no need to swap");
533*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
534*5113495bSYour Name 	}
535*5113495bSYour Name 
536*5113495bSYour Name 	mlo_sta_get_vdev_list(vdev, &vdev_count, vdev_list);
537*5113495bSYour Name 	for (idx = 0; idx < vdev_count; idx++) {
538*5113495bSYour Name 		if (wlan_vdev_get_id(vdev_list[idx]) != lswitch_req->vdev_id &&
539*5113495bSYour Name 		    qdf_test_bit(idx, sta_ctx->wlan_connected_links)) {
540*5113495bSYour Name 			wlan_vdev_mlme_clear_mlo_link_vdev(vdev_list[idx]);
541*5113495bSYour Name 			wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev);
542*5113495bSYour Name 			lswitch_req->restore_vdev_flag = true;
543*5113495bSYour Name 
544*5113495bSYour Name 			status = cb(assoc_vdev,
545*5113495bSYour Name 				    wlan_vdev_get_id(vdev_list[idx]));
546*5113495bSYour Name 			break;
547*5113495bSYour Name 		}
548*5113495bSYour Name 
549*5113495bSYour Name 		mlo_release_vdev_ref(vdev_list[idx]);
550*5113495bSYour Name 	}
551*5113495bSYour Name 
552*5113495bSYour Name 	for (; idx < vdev_count; idx++)
553*5113495bSYour Name 		mlo_release_vdev_ref(vdev_list[idx]);
554*5113495bSYour Name 
555*5113495bSYour Name 	return status;
556*5113495bSYour Name }
557*5113495bSYour Name 
558*5113495bSYour Name QDF_STATUS
mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * lswitch_req,enum wlan_mlo_link_switch_notify_reason notify_reason)559*5113495bSYour Name mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
560*5113495bSYour Name 				 struct wlan_mlo_link_switch_req *lswitch_req,
561*5113495bSYour Name 				 enum wlan_mlo_link_switch_notify_reason notify_reason)
562*5113495bSYour Name {
563*5113495bSYour Name 	QDF_STATUS status;
564*5113495bSYour Name 
565*5113495bSYour Name 	switch (notify_reason) {
566*5113495bSYour Name 	case MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER:
567*5113495bSYour Name 	case MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER:
568*5113495bSYour Name 		if (!mlo_check_if_all_vdev_up(vdev)) {
569*5113495bSYour Name 			mlo_debug("Not all VDEVs up");
570*5113495bSYour Name 			return QDF_STATUS_E_AGAIN;
571*5113495bSYour Name 		}
572*5113495bSYour Name 
573*5113495bSYour Name 		if (mlo_is_chan_switch_in_progress(vdev)) {
574*5113495bSYour Name 			mlo_debug("CSA is in progress on one of ML vdevs, abort link switch");
575*5113495bSYour Name 			return QDF_STATUS_E_AGAIN;
576*5113495bSYour Name 		}
577*5113495bSYour Name 
578*5113495bSYour Name 		if (notify_reason ==
579*5113495bSYour Name 		    MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) {
580*5113495bSYour Name 			return QDF_STATUS_SUCCESS;
581*5113495bSYour Name 		}
582*5113495bSYour Name 
583*5113495bSYour Name 		break;
584*5113495bSYour Name 	default:
585*5113495bSYour Name 		break;
586*5113495bSYour Name 	}
587*5113495bSYour Name 
588*5113495bSYour Name 	status = mlo_mgr_link_switch_osif_notification(vdev, lswitch_req);
589*5113495bSYour Name 
590*5113495bSYour Name 	return status;
591*5113495bSYour Name }
592*5113495bSYour Name 
mlo_mgr_link_switch_init(struct wlan_objmgr_psoc * psoc,struct wlan_mlo_dev_context * ml_dev)593*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_init(struct wlan_objmgr_psoc *psoc,
594*5113495bSYour Name 				    struct wlan_mlo_dev_context *ml_dev)
595*5113495bSYour Name {
596*5113495bSYour Name 	ml_dev->link_ctx =
597*5113495bSYour Name 		qdf_mem_malloc(sizeof(struct mlo_link_switch_context));
598*5113495bSYour Name 
599*5113495bSYour Name 	if (!ml_dev->link_ctx)
600*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
601*5113495bSYour Name 
602*5113495bSYour Name 	mlo_mgr_link_switch_init_state(ml_dev);
603*5113495bSYour Name 	mlo_mgr_alloc_link_info_wmi_chan(ml_dev);
604*5113495bSYour Name 	mlo_mgr_update_link_info_reset(psoc, ml_dev);
605*5113495bSYour Name 
606*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
607*5113495bSYour Name }
608*5113495bSYour Name 
mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context * ml_dev)609*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev)
610*5113495bSYour Name {
611*5113495bSYour Name 	mlo_mgr_free_link_info_wmi_chan(ml_dev);
612*5113495bSYour Name 	qdf_mem_free(ml_dev->link_ctx);
613*5113495bSYour Name 	ml_dev->link_ctx = NULL;
614*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
615*5113495bSYour Name }
616*5113495bSYour Name 
617*5113495bSYour Name void
mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev * vdev,int32_t link_id)618*5113495bSYour Name mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
619*5113495bSYour Name {
620*5113495bSYour Name 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
621*5113495bSYour Name 	struct mlo_link_info *link_info;
622*5113495bSYour Name 	QDF_STATUS(*osif_bss_update_cb)(struct qdf_mac_addr *self_mac,
623*5113495bSYour Name 					struct qdf_mac_addr *bssid,
624*5113495bSYour Name 					int32_t link_id);
625*5113495bSYour Name 
626*5113495bSYour Name 	if (!g_mlo_ctx || !vdev->mlo_dev_ctx || !g_mlo_ctx->osif_ops ||
627*5113495bSYour Name 	    !g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info)
628*5113495bSYour Name 		return;
629*5113495bSYour Name 
630*5113495bSYour Name 	link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id);
631*5113495bSYour Name 	if (!link_info)
632*5113495bSYour Name 		return;
633*5113495bSYour Name 
634*5113495bSYour Name 	mlo_debug("VDEV ID %d, Link ID %d, STA MAC " QDF_MAC_ADDR_FMT ", BSSID " QDF_MAC_ADDR_FMT,
635*5113495bSYour Name 		  link_info->vdev_id, link_id,
636*5113495bSYour Name 		  QDF_MAC_ADDR_REF(link_info->link_addr.bytes),
637*5113495bSYour Name 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
638*5113495bSYour Name 	osif_bss_update_cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info;
639*5113495bSYour Name 
640*5113495bSYour Name 	osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr,
641*5113495bSYour Name 			   link_id);
642*5113495bSYour Name }
643*5113495bSYour Name 
mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev * vdev,QDF_STATUS discon_status,bool is_link_switch_resp)644*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev,
645*5113495bSYour Name 					       QDF_STATUS discon_status,
646*5113495bSYour Name 					       bool is_link_switch_resp)
647*5113495bSYour Name {
648*5113495bSYour Name 	QDF_STATUS status;
649*5113495bSYour Name 	enum mlo_link_switch_req_state cur_state;
650*5113495bSYour Name 	struct mlo_link_info *new_link_info;
651*5113495bSYour Name 	struct qdf_mac_addr mac_addr, mld_addr;
652*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
653*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
654*5113495bSYour Name 
655*5113495bSYour Name 	if (!is_link_switch_resp) {
656*5113495bSYour Name 		mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx);
657*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
658*5113495bSYour Name 	}
659*5113495bSYour Name 
660*5113495bSYour Name 	cur_state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
661*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(discon_status) ||
662*5113495bSYour Name 	    cur_state != MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK) {
663*5113495bSYour Name 		mlo_err("VDEV %d link switch disconnect req failed",
664*5113495bSYour Name 			req->vdev_id);
665*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
666*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
667*5113495bSYour Name 	}
668*5113495bSYour Name 
669*5113495bSYour Name 	mlo_debug("VDEV %d link switch disconnect complete",
670*5113495bSYour Name 		  wlan_vdev_get_id(vdev));
671*5113495bSYour Name 
672*5113495bSYour Name 	new_link_info =
673*5113495bSYour Name 		mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
674*5113495bSYour Name 					       req->new_ieee_link_id);
675*5113495bSYour Name 	if (!new_link_info) {
676*5113495bSYour Name 		mlo_err("New link not found in mlo dev ctx");
677*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
678*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
679*5113495bSYour Name 	}
680*5113495bSYour Name 
681*5113495bSYour Name 	qdf_copy_macaddr(&mld_addr, &mlo_dev_ctx->mld_addr);
682*5113495bSYour Name 	qdf_copy_macaddr(&mac_addr, &new_link_info->link_addr);
683*5113495bSYour Name 
684*5113495bSYour Name 	status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
685*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
686*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
687*5113495bSYour Name 		return status;
688*5113495bSYour Name 	}
689*5113495bSYour Name 
690*5113495bSYour Name 	status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev);
691*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
692*5113495bSYour Name 		mlo_debug("VDEV %d set MAC addr FW request failed",
693*5113495bSYour Name 			  req->vdev_id);
694*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
695*5113495bSYour Name 	}
696*5113495bSYour Name 
697*5113495bSYour Name 	return status;
698*5113495bSYour Name }
699*5113495bSYour Name 
mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev * vdev,uint8_t resp_status)700*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
701*5113495bSYour Name 						 uint8_t resp_status)
702*5113495bSYour Name {
703*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
704*5113495bSYour Name 	enum mlo_link_switch_req_state cur_state;
705*5113495bSYour Name 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
706*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req;
707*5113495bSYour Name 	struct mlo_link_info *new_link_info;
708*5113495bSYour Name 
709*5113495bSYour Name 	if (resp_status) {
710*5113495bSYour Name 		mlo_err("VDEV %d set MAC address response %d",
711*5113495bSYour Name 			wlan_vdev_get_id(vdev), resp_status);
712*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
713*5113495bSYour Name 		return status;
714*5113495bSYour Name 	}
715*5113495bSYour Name 
716*5113495bSYour Name 	if (!g_mlo_ctx) {
717*5113495bSYour Name 		mlo_err("global mlo ctx NULL");
718*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
719*5113495bSYour Name 		return status;
720*5113495bSYour Name 	}
721*5113495bSYour Name 
722*5113495bSYour Name 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
723*5113495bSYour Name 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
724*5113495bSYour Name 	if (cur_state != MLO_LINK_SWITCH_STATE_SET_MAC_ADDR) {
725*5113495bSYour Name 		mlo_err("Link switch cmd flushed, there can be MAC addr mismatch with FW");
726*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
727*5113495bSYour Name 		return status;
728*5113495bSYour Name 	}
729*5113495bSYour Name 
730*5113495bSYour Name 	new_link_info =
731*5113495bSYour Name 		mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
732*5113495bSYour Name 					       req->new_ieee_link_id);
733*5113495bSYour Name 	if (!new_link_info) {
734*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
735*5113495bSYour Name 		return status;
736*5113495bSYour Name 	}
737*5113495bSYour Name 
738*5113495bSYour Name 	wlan_vdev_mlme_set_macaddr(vdev, new_link_info->link_addr.bytes);
739*5113495bSYour Name 	wlan_vdev_mlme_set_linkaddr(vdev, new_link_info->link_addr.bytes);
740*5113495bSYour Name 
741*5113495bSYour Name 	status = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_mac_addr(
742*5113495bSYour Name 							req->curr_ieee_link_id,
743*5113495bSYour Name 							req->new_ieee_link_id,
744*5113495bSYour Name 							req->vdev_id);
745*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
746*5113495bSYour Name 		mlo_debug("VDEV %d OSIF MAC addr update failed %d",
747*5113495bSYour Name 			  req->vdev_id, status);
748*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
749*5113495bSYour Name 		return status;
750*5113495bSYour Name 	}
751*5113495bSYour Name 
752*5113495bSYour Name 	status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
753*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
754*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
755*5113495bSYour Name 		return status;
756*5113495bSYour Name 	}
757*5113495bSYour Name 
758*5113495bSYour Name 	status = mlo_mgr_link_switch_start_connect(vdev);
759*5113495bSYour Name 
760*5113495bSYour Name 	return status;
761*5113495bSYour Name }
762*5113495bSYour Name 
mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev * vdev)763*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev)
764*5113495bSYour Name {
765*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
766*5113495bSYour Name 	struct wlan_cm_connect_req conn_req = {0};
767*5113495bSYour Name 	struct mlo_link_info *mlo_link_info;
768*5113495bSYour Name 	uint8_t *vdev_mac;
769*5113495bSYour Name 	struct wlan_mlo_sta *sta_ctx;
770*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
771*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
772*5113495bSYour Name 	struct wlan_objmgr_vdev *assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
773*5113495bSYour Name 
774*5113495bSYour Name 	if (!assoc_vdev) {
775*5113495bSYour Name 		mlo_err("Assoc VDEV not found");
776*5113495bSYour Name 		goto out;
777*5113495bSYour Name 	}
778*5113495bSYour Name 
779*5113495bSYour Name 	mlo_link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx,
780*5113495bSYour Name 						       req->new_ieee_link_id);
781*5113495bSYour Name 
782*5113495bSYour Name 	if (!mlo_link_info) {
783*5113495bSYour Name 		mlo_err("New link ID not found");
784*5113495bSYour Name 		goto out;
785*5113495bSYour Name 	}
786*5113495bSYour Name 
787*5113495bSYour Name 	vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev);
788*5113495bSYour Name 	if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr,
789*5113495bSYour Name 				  (struct qdf_mac_addr *)vdev_mac)) {
790*5113495bSYour Name 		mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT,
791*5113495bSYour Name 			QDF_MAC_ADDR_REF(vdev_mac),
792*5113495bSYour Name 			QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes));
793*5113495bSYour Name 		goto out;
794*5113495bSYour Name 	}
795*5113495bSYour Name 
796*5113495bSYour Name 	sta_ctx = mlo_dev_ctx->sta_ctx;
797*5113495bSYour Name 	copied_conn_req_lock_acquire(sta_ctx);
798*5113495bSYour Name 	if (sta_ctx->copied_conn_req) {
799*5113495bSYour Name 		qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req,
800*5113495bSYour Name 			     sizeof(struct wlan_cm_connect_req));
801*5113495bSYour Name 	} else {
802*5113495bSYour Name 		copied_conn_req_lock_release(sta_ctx);
803*5113495bSYour Name 		goto out;
804*5113495bSYour Name 	}
805*5113495bSYour Name 	copied_conn_req_lock_release(sta_ctx);
806*5113495bSYour Name 
807*5113495bSYour Name 	conn_req.vdev_id = wlan_vdev_get_id(vdev);
808*5113495bSYour Name 	conn_req.source = CM_MLO_LINK_SWITCH_CONNECT;
809*5113495bSYour Name 	wlan_vdev_set_link_id(vdev, req->new_ieee_link_id);
810*5113495bSYour Name 
811*5113495bSYour Name 	qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr);
812*5113495bSYour Name 	wlan_vdev_mlme_get_ssid(assoc_vdev, conn_req.ssid.ssid,
813*5113495bSYour Name 				&conn_req.ssid.length);
814*5113495bSYour Name 	status = wlan_vdev_get_bss_peer_mld_mac(assoc_vdev, &conn_req.mld_addr);
815*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
816*5113495bSYour Name 		mlo_debug("Get MLD addr failed");
817*5113495bSYour Name 		goto out;
818*5113495bSYour Name 	}
819*5113495bSYour Name 
820*5113495bSYour Name 	conn_req.crypto.auth_type = 0;
821*5113495bSYour Name 	conn_req.ml_parnter_info = sta_ctx->ml_partner_info;
822*5113495bSYour Name 	mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req);
823*5113495bSYour Name 
824*5113495bSYour Name 	status = wlan_cm_start_connect(vdev, &conn_req);
825*5113495bSYour Name 	if (QDF_IS_STATUS_SUCCESS(status))
826*5113495bSYour Name 		mlo_update_connected_links(vdev, 1);
827*5113495bSYour Name 
828*5113495bSYour Name 	wlan_cm_free_connect_req_param(&conn_req);
829*5113495bSYour Name 
830*5113495bSYour Name out:
831*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
832*5113495bSYour Name 		mlo_err("VDEV %d link switch connect request failed",
833*5113495bSYour Name 			wlan_vdev_get_id(vdev));
834*5113495bSYour Name 		mlo_mgr_remove_link_switch_cmd(vdev);
835*5113495bSYour Name 	}
836*5113495bSYour Name 
837*5113495bSYour Name 	return status;
838*5113495bSYour Name }
839*5113495bSYour Name 
840*5113495bSYour Name static void
mlo_mgr_link_switch_connect_success_trans_state(struct wlan_objmgr_vdev * vdev)841*5113495bSYour Name mlo_mgr_link_switch_connect_success_trans_state(struct wlan_objmgr_vdev *vdev)
842*5113495bSYour Name {
843*5113495bSYour Name 	enum mlo_link_switch_req_state curr_state;
844*5113495bSYour Name 
845*5113495bSYour Name 	/*
846*5113495bSYour Name 	 * If connection is success, then sending link switch failure to FW
847*5113495bSYour Name 	 * might result in not updating VDEV to link mapping in FW and FW may
848*5113495bSYour Name 	 * immediately send next link switch with params corresponding to
849*5113495bSYour Name 	 * pre-link switch which may vary post-link switch in host and might
850*5113495bSYour Name 	 * not be valid and results in Host-FW out-of-sync.
851*5113495bSYour Name 	 *
852*5113495bSYour Name 	 * Force the result of link switch in align with link switch connect
853*5113495bSYour Name 	 * so that Host and FW are not out of sync.
854*5113495bSYour Name 	 */
855*5113495bSYour Name 	mlo_dev_lock_acquire(vdev->mlo_dev_ctx);
856*5113495bSYour Name 	curr_state = vdev->mlo_dev_ctx->link_ctx->last_req.state;
857*5113495bSYour Name 	vdev->mlo_dev_ctx->link_ctx->last_req.state =
858*5113495bSYour Name 					MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS;
859*5113495bSYour Name 	mlo_dev_lock_release(vdev->mlo_dev_ctx);
860*5113495bSYour Name 
861*5113495bSYour Name 	if (curr_state != MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK)
862*5113495bSYour Name 		mlo_debug("Current link switch state %d changed", curr_state);
863*5113495bSYour Name }
864*5113495bSYour Name 
mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev * vdev,QDF_STATUS status)865*5113495bSYour Name void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
866*5113495bSYour Name 				      QDF_STATUS status)
867*5113495bSYour Name {
868*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req;
869*5113495bSYour Name 
870*5113495bSYour Name 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
871*5113495bSYour Name 	if (QDF_IS_STATUS_SUCCESS(status)) {
872*5113495bSYour Name 		mlo_mgr_link_switch_connect_success_trans_state(vdev);
873*5113495bSYour Name 	} else {
874*5113495bSYour Name 		mlo_update_connected_links(vdev, 0);
875*5113495bSYour Name 		mlo_err("VDEV %d link switch connect failed", req->vdev_id);
876*5113495bSYour Name 	}
877*5113495bSYour Name 
878*5113495bSYour Name 	mlo_mgr_remove_link_switch_cmd(vdev);
879*5113495bSYour Name 
880*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
881*5113495bSYour Name 		mlo_mgr_restore_rso_upon_link_switch_failure(
882*5113495bSYour Name 				wlan_mlo_get_assoc_link_vdev(vdev));
883*5113495bSYour Name }
884*5113495bSYour Name 
885*5113495bSYour Name static enum wlan_mlo_link_switch_notify_reason
mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev * vdev)886*5113495bSYour Name mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev *vdev)
887*5113495bSYour Name {
888*5113495bSYour Name 	enum mlo_link_switch_req_state curr_state;
889*5113495bSYour Name 	enum wlan_mlo_link_switch_notify_reason notify_reason;
890*5113495bSYour Name 
891*5113495bSYour Name 	curr_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
892*5113495bSYour Name 	switch (curr_state) {
893*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_IDLE:
894*5113495bSYour Name 		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER;
895*5113495bSYour Name 		break;
896*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_INIT:
897*5113495bSYour Name 		notify_reason =
898*5113495bSYour Name 			MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER;
899*5113495bSYour Name 		break;
900*5113495bSYour Name 	case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
901*5113495bSYour Name 		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS;
902*5113495bSYour Name 		break;
903*5113495bSYour Name 	default:
904*5113495bSYour Name 		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE;
905*5113495bSYour Name 		break;
906*5113495bSYour Name 	}
907*5113495bSYour Name 
908*5113495bSYour Name 	return notify_reason;
909*5113495bSYour Name }
910*5113495bSYour Name 
911*5113495bSYour Name static QDF_STATUS
mlo_mgr_start_link_switch(struct wlan_objmgr_vdev * vdev,struct wlan_serialization_command * cmd)912*5113495bSYour Name mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev,
913*5113495bSYour Name 			  struct wlan_serialization_command *cmd)
914*5113495bSYour Name {
915*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
916*5113495bSYour Name 	uint8_t vdev_id, old_link_id, new_link_id;
917*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
918*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
919*5113495bSYour Name 	struct qdf_mac_addr bssid;
920*5113495bSYour Name 
921*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
922*5113495bSYour Name 	old_link_id = req->curr_ieee_link_id;
923*5113495bSYour Name 	new_link_id = req->new_ieee_link_id;
924*5113495bSYour Name 
925*5113495bSYour Name 	mlo_debug("VDEV %d start link switch", vdev_id);
926*5113495bSYour Name 	mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
927*5113495bSYour Name 
928*5113495bSYour Name 	if (!wlan_cm_is_vdev_connected(vdev)) {
929*5113495bSYour Name 		mlo_err("VDEV %d not in connected state", vdev_id);
930*5113495bSYour Name 		return status;
931*5113495bSYour Name 	}
932*5113495bSYour Name 
933*5113495bSYour Name 	status = wlan_vdev_get_bss_peer_mac(vdev, &bssid);
934*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
935*5113495bSYour Name 		return status;
936*5113495bSYour Name 
937*5113495bSYour Name 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, &req->peer_mld_addr);
938*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
939*5113495bSYour Name 		return status;
940*5113495bSYour Name 
941*5113495bSYour Name 	status = mlo_mgr_link_switch_notify(vdev, req);
942*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
943*5113495bSYour Name 		return status;
944*5113495bSYour Name 
945*5113495bSYour Name 	wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev);
946*5113495bSYour Name 	status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
947*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
948*5113495bSYour Name 		return status;
949*5113495bSYour Name 
950*5113495bSYour Name 	status = wlan_cm_disconnect(vdev, CM_MLO_LINK_SWITCH_DISCONNECT,
951*5113495bSYour Name 				    REASON_FW_TRIGGERED_LINK_SWITCH, &bssid);
952*5113495bSYour Name 
953*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
954*5113495bSYour Name 		mlo_err("VDEV %d disconnect request not handled", req->vdev_id);
955*5113495bSYour Name 
956*5113495bSYour Name 	return status;
957*5113495bSYour Name }
958*5113495bSYour Name 
959*5113495bSYour Name static QDF_STATUS
mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command * cmd,enum wlan_serialization_cb_reason cb_reason)960*5113495bSYour Name mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
961*5113495bSYour Name 			   enum wlan_serialization_cb_reason cb_reason)
962*5113495bSYour Name {
963*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
964*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
965*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req;
966*5113495bSYour Name 	enum qdf_hang_reason reason = QDF_VDEV_ACTIVE_SER_LINK_SWITCH_TIMEOUT;
967*5113495bSYour Name 
968*5113495bSYour Name 	if (!cmd) {
969*5113495bSYour Name 		mlo_err("cmd is NULL, reason: %d", cb_reason);
970*5113495bSYour Name 		QDF_ASSERT(0);
971*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
972*5113495bSYour Name 	}
973*5113495bSYour Name 
974*5113495bSYour Name 	vdev = cmd->vdev;
975*5113495bSYour Name 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
976*5113495bSYour Name 
977*5113495bSYour Name 	switch (cb_reason) {
978*5113495bSYour Name 	case WLAN_SER_CB_ACTIVATE_CMD:
979*5113495bSYour Name 		status = mlo_mgr_start_link_switch(vdev, cmd);
980*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
981*5113495bSYour Name 			mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx);
982*5113495bSYour Name 			mlo_mgr_link_switch_notify(vdev, req);
983*5113495bSYour Name 		}
984*5113495bSYour Name 		break;
985*5113495bSYour Name 	case WLAN_SER_CB_RELEASE_MEM_CMD:
986*5113495bSYour Name 		mlo_mgr_link_switch_complete(vdev);
987*5113495bSYour Name 		break;
988*5113495bSYour Name 	case WLAN_SER_CB_CANCEL_CMD:
989*5113495bSYour Name 		mlo_err("Link switch cmd cancelled");
990*5113495bSYour Name 		break;
991*5113495bSYour Name 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
992*5113495bSYour Name 		mlo_err("Link switch active cmd timeout");
993*5113495bSYour Name 		wlan_cm_trigger_panic_on_cmd_timeout(vdev, reason);
994*5113495bSYour Name 		break;
995*5113495bSYour Name 	default:
996*5113495bSYour Name 		QDF_ASSERT(0);
997*5113495bSYour Name 		mlo_mgr_link_switch_complete(vdev);
998*5113495bSYour Name 		break;
999*5113495bSYour Name 	}
1000*5113495bSYour Name 
1001*5113495bSYour Name 	return status;
1002*5113495bSYour Name }
1003*5113495bSYour Name 
mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev * vdev)1004*5113495bSYour Name void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
1005*5113495bSYour Name {
1006*5113495bSYour Name 	struct wlan_serialization_queued_cmd_info cmd_info;
1007*5113495bSYour Name 	enum mlo_link_switch_req_state cur_state;
1008*5113495bSYour Name 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
1009*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req;
1010*5113495bSYour Name 
1011*5113495bSYour Name 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
1012*5113495bSYour Name 	if (cur_state == MLO_LINK_SWITCH_STATE_IDLE)
1013*5113495bSYour Name 		return;
1014*5113495bSYour Name 
1015*5113495bSYour Name 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
1016*5113495bSYour Name 	mlo_mgr_link_switch_notify(vdev, req);
1017*5113495bSYour Name 
1018*5113495bSYour Name 	/* Force queue disconnect on failure */
1019*5113495bSYour Name 	if (cur_state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS &&
1020*5113495bSYour Name 	    cur_state >= MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK &&
1021*5113495bSYour Name 	    !wlan_cm_is_vdev_connected(vdev)) {
1022*5113495bSYour Name 		mlo_mgr_link_switch_defer_disconnect_req(vdev,
1023*5113495bSYour Name 							 CM_MLME_DISCONNECT,
1024*5113495bSYour Name 							 REASON_HOST_TRIGGERED_LINK_DELETE);
1025*5113495bSYour Name 	}
1026*5113495bSYour Name 
1027*5113495bSYour Name 	/* Handle any pending disconnect */
1028*5113495bSYour Name 	mlo_handle_pending_disconnect(vdev);
1029*5113495bSYour Name 
1030*5113495bSYour Name 	if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) {
1031*5113495bSYour Name 		mlo_debug("Link switch not serialized");
1032*5113495bSYour Name 		mlo_mgr_link_switch_complete(vdev);
1033*5113495bSYour Name 		return;
1034*5113495bSYour Name 	}
1035*5113495bSYour Name 
1036*5113495bSYour Name 	cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
1037*5113495bSYour Name 			  (req->curr_ieee_link_id);
1038*5113495bSYour Name 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
1039*5113495bSYour Name 	cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
1040*5113495bSYour Name 	cmd_info.vdev = vdev;
1041*5113495bSYour Name 	cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
1042*5113495bSYour Name 
1043*5113495bSYour Name 	wlan_serialization_remove_cmd(&cmd_info);
1044*5113495bSYour Name }
1045*5113495bSYour Name 
1046*5113495bSYour Name #define MLO_MGR_MAX_LSWITCH_TIMEOUT	35000
1047*5113495bSYour Name 
mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * req)1048*5113495bSYour Name QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
1049*5113495bSYour Name 				       struct wlan_mlo_link_switch_req *req)
1050*5113495bSYour Name {
1051*5113495bSYour Name 	QDF_STATUS status;
1052*5113495bSYour Name 	enum wlan_serialization_status ser_cmd_status;
1053*5113495bSYour Name 	struct wlan_serialization_command cmd = {0};
1054*5113495bSYour Name 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
1055*5113495bSYour Name 	struct mlo_link_switch_context *link_ctx;
1056*5113495bSYour Name 
1057*5113495bSYour Name 	if (!vdev->mlo_dev_ctx) {
1058*5113495bSYour Name 		mlo_err("ML dev ctx NULL, reject link switch");
1059*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1060*5113495bSYour Name 	}
1061*5113495bSYour Name 
1062*5113495bSYour Name 	link_ctx = vdev->mlo_dev_ctx->link_ctx;
1063*5113495bSYour Name 	link_ctx->last_req = *req;
1064*5113495bSYour Name 
1065*5113495bSYour Name 	cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
1066*5113495bSYour Name 	cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
1067*5113495bSYour Name 		     (req->curr_ieee_link_id);
1068*5113495bSYour Name 	cmd.cmd_cb = mlo_mgr_ser_link_switch_cb;
1069*5113495bSYour Name 	cmd.source = WLAN_UMAC_COMP_MLO_MGR;
1070*5113495bSYour Name 	cmd.is_high_priority = false;
1071*5113495bSYour Name 	cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT;
1072*5113495bSYour Name 	cmd.vdev = vdev;
1073*5113495bSYour Name 	cmd.is_blocking = true;
1074*5113495bSYour Name 
1075*5113495bSYour Name 	if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) {
1076*5113495bSYour Name 		mlo_debug("Do not serialize link switch");
1077*5113495bSYour Name 		status = mlo_mgr_start_link_switch(vdev, &cmd);
1078*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1079*5113495bSYour Name 			mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx);
1080*5113495bSYour Name 			mlo_mgr_link_switch_notify(vdev, req);
1081*5113495bSYour Name 		}
1082*5113495bSYour Name 		return status;
1083*5113495bSYour Name 	}
1084*5113495bSYour Name 
1085*5113495bSYour Name 	ser_cmd_status = wlan_serialization_request(&cmd);
1086*5113495bSYour Name 	switch (ser_cmd_status) {
1087*5113495bSYour Name 	case WLAN_SER_CMD_PENDING:
1088*5113495bSYour Name 		mlo_debug("Link switch cmd in pending queue");
1089*5113495bSYour Name 		break;
1090*5113495bSYour Name 	case WLAN_SER_CMD_ACTIVE:
1091*5113495bSYour Name 		mlo_debug("Link switch cmd in active queue");
1092*5113495bSYour Name 		break;
1093*5113495bSYour Name 	default:
1094*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1095*5113495bSYour Name 	}
1096*5113495bSYour Name 
1097*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1098*5113495bSYour Name }
1099*5113495bSYour Name 
mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * req)1100*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev,
1101*5113495bSYour Name 				      struct wlan_mlo_link_switch_req *req)
1102*5113495bSYour Name {
1103*5113495bSYour Name 	int8_t i;
1104*5113495bSYour Name 	QDF_STATUS status, ret_status = QDF_STATUS_SUCCESS;
1105*5113495bSYour Name 	enum wlan_mlo_link_switch_notify_reason notify_reason;
1106*5113495bSYour Name 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
1107*5113495bSYour Name 
1108*5113495bSYour Name 	if (!mlo_mgr_ctx) {
1109*5113495bSYour Name 		mlo_err("Global mlo mgr NULL");
1110*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
1111*5113495bSYour Name 	}
1112*5113495bSYour Name 
1113*5113495bSYour Name 	notify_reason = mlo_mgr_link_switch_get_notify_reason(vdev);
1114*5113495bSYour Name 	for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) {
1115*5113495bSYour Name 		if (!mlo_mgr_ctx->lswitch_notifier[i].in_use)
1116*5113495bSYour Name 			continue;
1117*5113495bSYour Name 
1118*5113495bSYour Name 		status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req,
1119*5113495bSYour Name 							     notify_reason);
1120*5113495bSYour Name 		if (QDF_IS_STATUS_SUCCESS(status))
1121*5113495bSYour Name 			continue;
1122*5113495bSYour Name 
1123*5113495bSYour Name 		mlo_debug("Link switch notify %d failed in %d",
1124*5113495bSYour Name 			  notify_reason, i);
1125*5113495bSYour Name 		ret_status = status;
1126*5113495bSYour Name 		if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER)
1127*5113495bSYour Name 			break;
1128*5113495bSYour Name 	}
1129*5113495bSYour Name 
1130*5113495bSYour Name 	return ret_status;
1131*5113495bSYour Name }
1132*5113495bSYour Name 
1133*5113495bSYour Name QDF_STATUS
mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * req)1134*5113495bSYour Name mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
1135*5113495bSYour Name 				     struct wlan_mlo_link_switch_req *req)
1136*5113495bSYour Name {
1137*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
1138*5113495bSYour Name 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
1139*5113495bSYour Name 	struct mlo_link_info *new_link_info;
1140*5113495bSYour Name 
1141*5113495bSYour Name 	if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID ||
1142*5113495bSYour Name 	    req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) {
1143*5113495bSYour Name 		mlo_err("Invalid link params, curr link id %d, new link id %d",
1144*5113495bSYour Name 			req->curr_ieee_link_id, req->new_ieee_link_id);
1145*5113495bSYour Name 		return status;
1146*5113495bSYour Name 	}
1147*5113495bSYour Name 
1148*5113495bSYour Name 	new_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
1149*5113495bSYour Name 						       req->new_ieee_link_id);
1150*5113495bSYour Name 	if (!new_link_info) {
1151*5113495bSYour Name 		mlo_err("New link id %d not part of association",
1152*5113495bSYour Name 			req->new_ieee_link_id);
1153*5113495bSYour Name 		return status;
1154*5113495bSYour Name 	}
1155*5113495bSYour Name 
1156*5113495bSYour Name 	if (new_link_info->vdev_id != WLAN_INVALID_VDEV_ID) {
1157*5113495bSYour Name 		mlo_err("requested link already active on other vdev:%d",
1158*5113495bSYour Name 			new_link_info->vdev_id);
1159*5113495bSYour Name 		return status;
1160*5113495bSYour Name 	}
1161*5113495bSYour Name 
1162*5113495bSYour Name 	if (!mlo_is_mld_sta(vdev)) {
1163*5113495bSYour Name 		mlo_err("Link switch req not valid for VDEV %d", vdev_id);
1164*5113495bSYour Name 		return status;
1165*5113495bSYour Name 	}
1166*5113495bSYour Name 
1167*5113495bSYour Name 	if (!wlan_cm_is_vdev_connected(vdev)) {
1168*5113495bSYour Name 		mlo_err("VDEV %d not in connected state", vdev_id);
1169*5113495bSYour Name 		return status;
1170*5113495bSYour Name 	}
1171*5113495bSYour Name 
1172*5113495bSYour Name 	if (mlo_mgr_is_link_switch_in_progress(vdev)) {
1173*5113495bSYour Name 		mlo_err("Link switch already in progress");
1174*5113495bSYour Name 		return status;
1175*5113495bSYour Name 	}
1176*5113495bSYour Name 
1177*5113495bSYour Name 	if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) {
1178*5113495bSYour Name 		mlo_err("VDEV %d link id wrong, curr link id %d",
1179*5113495bSYour Name 			vdev_id, wlan_vdev_get_link_id(vdev));
1180*5113495bSYour Name 		return status;
1181*5113495bSYour Name 	}
1182*5113495bSYour Name 
1183*5113495bSYour Name 	/* Notify callers on the new link switch request before serializing */
1184*5113495bSYour Name 	status = mlo_mgr_link_switch_notify(vdev, req);
1185*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1186*5113495bSYour Name 		mlo_err("Link switch rejected in pre-serialize notify");
1187*5113495bSYour Name 		return status;
1188*5113495bSYour Name 	}
1189*5113495bSYour Name 
1190*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1191*5113495bSYour Name }
1192*5113495bSYour Name 
mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc * psoc,void * evt_params)1193*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc,
1194*5113495bSYour Name 					      void *evt_params)
1195*5113495bSYour Name {
1196*5113495bSYour Name 	QDF_STATUS status;
1197*5113495bSYour Name 	struct wlan_mlo_link_switch_cnf cnf_params = {0};
1198*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req;
1199*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
1200*5113495bSYour Name 
1201*5113495bSYour Name 	if (!evt_params) {
1202*5113495bSYour Name 		mlo_err("Invalid params");
1203*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1204*5113495bSYour Name 	}
1205*5113495bSYour Name 
1206*5113495bSYour Name 	req = (struct wlan_mlo_link_switch_req *)evt_params;
1207*5113495bSYour Name 
1208*5113495bSYour Name 	/* The reference is released on Link Switch status confirm to FW */
1209*5113495bSYour Name 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id,
1210*5113495bSYour Name 						    WLAN_MLO_MGR_ID);
1211*5113495bSYour Name 	if (!vdev) {
1212*5113495bSYour Name 		mlo_err("Invalid link switch VDEV %d", req->vdev_id);
1213*5113495bSYour Name 
1214*5113495bSYour Name 		/* Fill reject params here and send to FW as VDEV is invalid */
1215*5113495bSYour Name 		cnf_params.vdev_id = req->vdev_id;
1216*5113495bSYour Name 		cnf_params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
1217*5113495bSYour Name 		mlo_mgr_link_switch_send_cnf_cmd(psoc, &cnf_params);
1218*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1219*5113495bSYour Name 	}
1220*5113495bSYour Name 
1221*5113495bSYour Name 	mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d",
1222*5113495bSYour Name 		  req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id,
1223*5113495bSYour Name 		  req->new_primary_freq, req->new_phymode, req->reason);
1224*5113495bSYour Name 
1225*5113495bSYour Name 	status = mlo_mgr_link_switch_validate_request(vdev, req);
1226*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1227*5113495bSYour Name 		mlo_debug("Link switch params/request invalid");
1228*5113495bSYour Name 		mlo_mgr_link_switch_complete(vdev);
1229*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1230*5113495bSYour Name 	}
1231*5113495bSYour Name 
1232*5113495bSYour Name 	status = mlo_mgr_ser_link_switch_cmd(vdev, req);
1233*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1234*5113495bSYour Name 		mlo_err("Failed to serialize link switch command");
1235*5113495bSYour Name 		mlo_mgr_link_switch_complete(vdev);
1236*5113495bSYour Name 	}
1237*5113495bSYour Name 
1238*5113495bSYour Name 	return status;
1239*5113495bSYour Name }
1240*5113495bSYour Name 
1241*5113495bSYour Name #define IS_LINK_SET(link_bitmap, link_id) ((link_bitmap) & (BIT(link_id)))
1242*5113495bSYour Name 
mlo_mgr_update_link_state(struct wlan_mlo_dev_context * mld_ctx,uint32_t active_link_bitmap)1243*5113495bSYour Name static void mlo_mgr_update_link_state(struct wlan_mlo_dev_context *mld_ctx,
1244*5113495bSYour Name 				      uint32_t active_link_bitmap)
1245*5113495bSYour Name {
1246*5113495bSYour Name 	uint8_t i;
1247*5113495bSYour Name 	struct mlo_link_info *link_info;
1248*5113495bSYour Name 
1249*5113495bSYour Name 	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
1250*5113495bSYour Name 		link_info = &mld_ctx->link_ctx->links_info[i];
1251*5113495bSYour Name 
1252*5113495bSYour Name 		if (IS_LINK_SET(active_link_bitmap, link_info->link_id))
1253*5113495bSYour Name 			link_info->is_link_active = true;
1254*5113495bSYour Name 		else
1255*5113495bSYour Name 			link_info->is_link_active = false;
1256*5113495bSYour Name 	}
1257*5113495bSYour Name }
1258*5113495bSYour Name 
1259*5113495bSYour Name QDF_STATUS
mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc * psoc,struct mlo_link_switch_state_info * info)1260*5113495bSYour Name mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc *psoc,
1261*5113495bSYour Name 				       struct mlo_link_switch_state_info *info)
1262*5113495bSYour Name {
1263*5113495bSYour Name 	uint8_t i;
1264*5113495bSYour Name 	struct wlan_mlo_dev_context *mld_ctx = NULL;
1265*5113495bSYour Name 
1266*5113495bSYour Name 	wlan_mlo_get_mlpeer_by_peer_mladdr(
1267*5113495bSYour Name 			&info->link_switch_param[0].mld_addr, &mld_ctx);
1268*5113495bSYour Name 
1269*5113495bSYour Name 	if (!mld_ctx) {
1270*5113495bSYour Name 		mlo_err("mlo dev ctx for mld_mac: " QDF_MAC_ADDR_FMT " not found",
1271*5113495bSYour Name 			QDF_MAC_ADDR_REF(info->link_switch_param[0].mld_addr.bytes));
1272*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1273*5113495bSYour Name 	}
1274*5113495bSYour Name 
1275*5113495bSYour Name 	for (i = 0; i < info->num_params; i++) {
1276*5113495bSYour Name 		wlan_connectivity_mld_link_status_event(
1277*5113495bSYour Name 				psoc,
1278*5113495bSYour Name 				&info->link_switch_param[i]);
1279*5113495bSYour Name 		mlo_mgr_update_link_state(
1280*5113495bSYour Name 				mld_ctx,
1281*5113495bSYour Name 				info->link_switch_param[i].active_link_bitmap);
1282*5113495bSYour Name 	}
1283*5113495bSYour Name 
1284*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1285*5113495bSYour Name }
1286*5113495bSYour Name 
mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev * vdev)1287*5113495bSYour Name QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev)
1288*5113495bSYour Name {
1289*5113495bSYour Name 	enum mlo_link_switch_req_state state;
1290*5113495bSYour Name 	struct wlan_mlo_link_switch_cnf params = {0};
1291*5113495bSYour Name 	struct mlo_link_switch_context *link_ctx;
1292*5113495bSYour Name 	struct wlan_mlo_link_switch_req *req;
1293*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1294*5113495bSYour Name 
1295*5113495bSYour Name 	/* Not checking NULL value as reference is already taken for vdev */
1296*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1297*5113495bSYour Name 
1298*5113495bSYour Name 	link_ctx = vdev->mlo_dev_ctx->link_ctx;
1299*5113495bSYour Name 	req = &link_ctx->last_req;
1300*5113495bSYour Name 
1301*5113495bSYour Name 	state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
1302*5113495bSYour Name 	if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS)
1303*5113495bSYour Name 		params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
1304*5113495bSYour Name 	else
1305*5113495bSYour Name 		params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT;
1306*5113495bSYour Name 
1307*5113495bSYour Name 	params.vdev_id = wlan_vdev_get_id(vdev);
1308*5113495bSYour Name 	params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED;
1309*5113495bSYour Name 
1310*5113495bSYour Name 	mlo_mgr_link_switch_send_cnf_cmd(psoc, &params);
1311*5113495bSYour Name 
1312*5113495bSYour Name 	mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx);
1313*5113495bSYour Name 	wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev);
1314*5113495bSYour Name 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1315*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1316*5113495bSYour Name }
1317*5113495bSYour Name 
1318*5113495bSYour Name QDF_STATUS
mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc * psoc,struct wlan_mlo_link_switch_cnf * cnf_params)1319*5113495bSYour Name mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc,
1320*5113495bSYour Name 				 struct wlan_mlo_link_switch_cnf *cnf_params)
1321*5113495bSYour Name {
1322*5113495bSYour Name 	QDF_STATUS status;
1323*5113495bSYour Name 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
1324*5113495bSYour Name 
1325*5113495bSYour Name 	mlo_debug("VDEV %d link switch completed, %s", cnf_params->vdev_id,
1326*5113495bSYour Name 		  (cnf_params->status == MLO_LINK_SWITCH_CNF_STATUS_ACCEPT) ?
1327*5113495bSYour Name 		  "success" : "fail");
1328*5113495bSYour Name 
1329*5113495bSYour Name 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
1330*5113495bSYour Name 	if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) {
1331*5113495bSYour Name 		mlo_err("handler is not registered");
1332*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1333*5113495bSYour Name 	}
1334*5113495bSYour Name 
1335*5113495bSYour Name 	status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, cnf_params);
1336*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
1337*5113495bSYour Name 		mlo_err("Link switch status update to FW failed");
1338*5113495bSYour Name 
1339*5113495bSYour Name 	return status;
1340*5113495bSYour Name }
1341*5113495bSYour Name 
1342*5113495bSYour Name QDF_STATUS
mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason)1343*5113495bSYour Name mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev,
1344*5113495bSYour Name 					 enum wlan_cm_source source,
1345*5113495bSYour Name 					 enum wlan_reason_code reason)
1346*5113495bSYour Name {
1347*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1348*5113495bSYour Name 	struct wlan_mlo_sta *sta_ctx;
1349*5113495bSYour Name 
1350*5113495bSYour Name 	if (!mlo_mgr_is_link_switch_in_progress(vdev)) {
1351*5113495bSYour Name 		mlo_info("Link switch not in progress");
1352*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1353*5113495bSYour Name 	}
1354*5113495bSYour Name 
1355*5113495bSYour Name 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1356*5113495bSYour Name 	sta_ctx = mlo_dev_ctx->sta_ctx;
1357*5113495bSYour Name 
1358*5113495bSYour Name 	if (!sta_ctx) {
1359*5113495bSYour Name 		mlo_err("sta ctx null");
1360*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
1361*5113495bSYour Name 	}
1362*5113495bSYour Name 
1363*5113495bSYour Name 	/* Move current link switch to abort state */
1364*5113495bSYour Name 	mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx);
1365*5113495bSYour Name 
1366*5113495bSYour Name 	if (sta_ctx->disconn_req) {
1367*5113495bSYour Name 		mlo_debug("Pending disconnect from source %d, reason %d",
1368*5113495bSYour Name 			  sta_ctx->disconn_req->source,
1369*5113495bSYour Name 			  sta_ctx->disconn_req->reason_code);
1370*5113495bSYour Name 		return QDF_STATUS_E_ALREADY;
1371*5113495bSYour Name 	}
1372*5113495bSYour Name 
1373*5113495bSYour Name 	sta_ctx->disconn_req =
1374*5113495bSYour Name 			qdf_mem_malloc(sizeof(struct wlan_cm_disconnect_req));
1375*5113495bSYour Name 	if (!sta_ctx->disconn_req)
1376*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
1377*5113495bSYour Name 
1378*5113495bSYour Name 	sta_ctx->disconn_req->vdev_id = wlan_vdev_get_id(vdev);
1379*5113495bSYour Name 	sta_ctx->disconn_req->source = source;
1380*5113495bSYour Name 	sta_ctx->disconn_req->reason_code = reason;
1381*5113495bSYour Name 
1382*5113495bSYour Name 	mlo_debug("Deferred disconnect source: %d, reason: %d", source, reason);
1383*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1384*5113495bSYour Name }
1385*5113495bSYour Name #endif
1386