Browse Source

qcacmn: MLO setup, teardown sequence changes

MLO setup, teardown sequence changes

Change-Id: I76d14cd66c373b3b734a17e44f3655ffd17893c5
CRs-Fixed: 3059859
Kiran Venkatappa 3 năm trước cách đây
mục cha
commit
3e3ed9ca89

+ 22 - 0
target_if/core/inc/target_if.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -2764,6 +2765,27 @@ uint16_t  target_if_pdev_get_hw_link_id
  */
 void target_pdev_set_hw_link_id
 		(struct wlan_objmgr_pdev *pdev, uint16_t hw_link_id);
+
+/**
+ * target_if_mlo_setup_req - API to trigger MLO setup sequence
+ * @pdev: Array of pointers to pdev object that are part of ML group
+ * @num_pdevs: Number of pdevs in above array
+ * @grp_id: ML Group ID
+ *
+ * Return: QDF_STATUS codes
+ */
+QDF_STATUS target_if_mlo_setup_req(struct wlan_objmgr_pdev **pdev,
+				   uint8_t num_pdevs, uint8_t grp_id);
+
+/**
+ * target_if_mlo_ready - API to send MLO ready
+ * @pdev: Array of pointers to pdev object that are part of ML group
+ * @num_pdevs: Number of pdevs in above array
+ *
+ * Return: QDF_STATUS codes
+ */
+QDF_STATUS target_if_mlo_ready(struct wlan_objmgr_pdev **pdev,
+			       uint8_t num_pdevs);
 #endif /*WLAN_FEATURE_11BE_MLO && WLAN_MLO_MULTI_CHIP*/
 
 #endif

+ 67 - 0
target_if/core/src/target_if_main.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -99,6 +100,8 @@
 #include <target_if_mgmt_txrx.h>
 #endif /* WLAN_MGMT_RX_REO_SUPPORT */
 
+#include "wmi_unified_api.h"
+
 static struct target_if_ctx *g_target_if_ctx;
 
 struct target_if_ctx *target_if_get_ctx()
@@ -915,4 +918,68 @@ void target_pdev_set_hw_link_id(struct wlan_objmgr_pdev *pdev,
 
 	tgt_pdev_info->hw_link_id  = hw_link_id;
 }
+
+static QDF_STATUS target_if_mlo_setup_send(struct wlan_objmgr_pdev *pdev,
+					   struct wlan_objmgr_pdev **pdev_list,
+					   uint8_t num_links, uint8_t grp_id)
+{
+	wmi_unified_t wmi_handle;
+	struct wmi_mlo_setup_params params = {0};
+	uint8_t idx, num_valid_links = 0;
+
+	wmi_handle = lmac_get_pdev_wmi_handle(pdev);
+	if (!wmi_handle)
+		return QDF_STATUS_E_INVAL;
+
+	params.mld_grp_id = grp_id;
+	params.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+
+	for (idx = 0; idx < num_links; idx++) {
+		if (pdev == pdev_list[idx])
+			continue;
+
+		params.partner_links[num_valid_links] =
+			target_if_pdev_get_hw_link_id(pdev_list[idx]);
+		num_valid_links++;
+	}
+	params.num_valid_hw_links = num_valid_links;
+
+	return wmi_mlo_setup_cmd_send(wmi_handle, &params);
+}
+
+QDF_STATUS target_if_mlo_setup_req(struct wlan_objmgr_pdev **pdev,
+				   uint8_t num_pdevs, uint8_t grp_id)
+{
+	uint8_t idx;
+
+	for (idx = 0; idx < num_pdevs; idx++)
+		target_if_mlo_setup_send(pdev[idx], pdev, num_pdevs, grp_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS target_if_mlo_ready_send(struct wlan_objmgr_pdev *pdev)
+{
+	wmi_unified_t wmi_handle;
+	struct wmi_mlo_ready_params params = {0};
+
+	wmi_handle = lmac_get_pdev_wmi_handle(pdev);
+	if (!wmi_handle)
+		return QDF_STATUS_E_INVAL;
+
+	params.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+
+	return wmi_mlo_ready_cmd_send(wmi_handle, &params);
+}
+
+QDF_STATUS target_if_mlo_ready(struct wlan_objmgr_pdev **pdev,
+			       uint8_t num_pdevs)
+{
+	uint8_t idx;
+
+	for (idx = 0; idx < num_pdevs; idx++)
+		target_if_mlo_ready_send(pdev[idx]);
+
+	return QDF_STATUS_SUCCESS;
+}
 #endif /*WLAN_FEATURE_11BE_MLO && WLAN_MLO_MULTI_CHIP*/

+ 142 - 0
target_if/init_deinit/src/init_event_handler.c

@@ -34,6 +34,10 @@
 #include <init_cmd_api.h>
 #include <cdp_txrx_cmn.h>
 #include <wlan_reg_ucfg_api.h>
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+#include <wlan_mlo_mgr_cmn.h>
+#include <wlan_mlo_mgr_setup.h>
+#endif
 
 static void init_deinit_set_send_init_cmd(struct wlan_objmgr_psoc *psoc,
 					  struct target_psoc_info *tgt_hdl)
@@ -531,6 +535,38 @@ static int init_deinit_service_available_handler(ol_scn_t scn_handle,
 	return 0;
 }
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+static void init_deinit_mlo_update_soc_ready(struct wlan_objmgr_psoc *psoc)
+{
+	mlo_setup_update_soc_ready(wlan_psoc_get_id(psoc));
+}
+
+static void init_deinit_send_ml_link_ready(struct wlan_objmgr_psoc *psoc,
+					   void *object, void *arg)
+{
+	struct wlan_objmgr_pdev *pdev = object;
+
+	qdf_assert_always(psoc);
+	qdf_assert_always(pdev);
+
+	mlo_setup_link_ready(pdev);
+}
+
+static void init_deinit_mlo_update_pdev_ready(struct wlan_objmgr_psoc *psoc,
+					      uint8_t num_radios)
+{
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
+				     init_deinit_send_ml_link_ready,
+				     NULL, 0, WLAN_INIT_DEINIT_ID);
+}
+#else
+static void init_deinit_mlo_update_soc_ready(struct wlan_objmgr_psoc *psoc)
+{}
+static void init_deinit_mlo_update_pdev_ready(struct wlan_objmgr_psoc *psoc,
+					      uint8_t num_radios)
+{}
+#endif /*WLAN_FEATURE_11BE_MLO && WLAN_MLO_MULTI_CHIP*/
+
 /* MAC address fourth byte index */
 #define MAC_BYTE_4 4
 
@@ -609,6 +645,8 @@ static int init_deinit_ready_event_handler(ol_scn_t scn_handle,
 			goto exit;
 		}
 
+	init_deinit_mlo_update_soc_ready(psoc);
+
 	num_radios = target_psoc_get_num_radios(tgt_hdl);
 
 	if ((ready_ev.num_total_peer != 0) &&
@@ -726,6 +764,7 @@ static int init_deinit_ready_event_handler(ol_scn_t scn_handle,
 			wlan_psoc_set_hw_macaddr(psoc, myaddr);
 	}
 
+	init_deinit_mlo_update_pdev_ready(psoc, num_radios);
 out:
 	target_if_btcoex_cfg_enable(psoc, tgt_hdl, event);
 	tgt_hdl->info.wmi_ready = TRUE;
@@ -735,6 +774,108 @@ exit:
 	return 0;
 }
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+static int init_deinit_mlo_setup_comp_event_handler(ol_scn_t scn_handle,
+						    uint8_t *event,
+						    uint32_t data_len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_pdev *pdev;
+	struct target_psoc_info *tgt_hdl;
+	struct wmi_unified *wmi_handle;
+	struct wmi_mlo_setup_complete_params params;
+
+	if (!scn_handle) {
+		target_if_err("scn handle NULL");
+		return -EINVAL;
+	}
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn_handle);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
+	if (!tgt_hdl) {
+		target_if_err("target_psoc_info is null");
+		return -EINVAL;
+	}
+	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
+
+	if (wmi_extract_mlo_setup_cmpl_event(wmi_handle, event, &params) !=
+			QDF_STATUS_SUCCESS)
+		return -EINVAL;
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, params.pdev_id,
+					  WLAN_INIT_DEINIT_ID);
+	if (pdev) {
+		mlo_link_setup_complete(pdev);
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_INIT_DEINIT_ID);
+	}
+
+	return 0;
+}
+
+static int init_deinit_mlo_teardown_comp_event_handler(ol_scn_t scn_handle,
+						       uint8_t *event,
+						       uint32_t data_len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_pdev *pdev;
+	struct target_psoc_info *tgt_hdl;
+	struct wmi_unified *wmi_handle;
+	struct wmi_mlo_teardown_cmpl_params params;
+
+	if (!scn_handle) {
+		target_if_err("scn handle NULL");
+		return -EINVAL;
+	}
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn_handle);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
+	if (!tgt_hdl) {
+		target_if_err("target_psoc_info is null");
+		return -EINVAL;
+	}
+	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
+
+	if (wmi_extract_mlo_teardown_cmpl_event(wmi_handle, event, &params) !=
+			QDF_STATUS_SUCCESS)
+		return -EINVAL;
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, params.pdev_id,
+					  WLAN_INIT_DEINIT_ID);
+	if (pdev) {
+		mlo_link_teardown_complete(pdev);
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_INIT_DEINIT_ID);
+	}
+
+	return 0;
+}
+
+static QDF_STATUS init_deinit_register_mlo_ev_handlers(wmi_unified_t wmi_handle)
+{
+	wmi_unified_register_event(wmi_handle,
+				   wmi_mlo_setup_complete_event_id,
+				   init_deinit_mlo_setup_comp_event_handler);
+	wmi_unified_register_event(wmi_handle,
+				   wmi_mlo_teardown_complete_event_id,
+				   init_deinit_mlo_teardown_comp_event_handler);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS init_deinit_register_mlo_ev_handlers(wmi_unified_t wmi_handle)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif /*WLAN_FEATURE_11BE_MLO && WLAN_MLO_MULTI_CHIP*/
 
 QDF_STATUS init_deinit_register_tgt_psoc_ev_handlers(
 				struct wlan_objmgr_psoc *psoc)
@@ -777,6 +918,7 @@ QDF_STATUS init_deinit_register_tgt_psoc_ev_handlers(
 				wmi_service_ready_ext2_event_id,
 				init_deinit_service_ext2_ready_event_handler,
 				WMI_RX_WORK_CTX);
+	retval = init_deinit_register_mlo_ev_handlers(wmi_handle);
 
 
 	return retval;

+ 5 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -484,6 +484,11 @@ struct wlan_lmac_if_mlme_tx_ops {
 				enum wlan_vdev_mgr_tgt_if_rsp_bit clear_bit);
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
 	uint16_t (*get_hw_link_id)(struct wlan_objmgr_pdev *pdev);
+	QDF_STATUS (*target_if_mlo_setup_req)(struct wlan_objmgr_pdev **pdev,
+					      uint8_t num_pdevs,
+					      uint8_t grp_id);
+	QDF_STATUS (*target_if_mlo_ready)(struct wlan_objmgr_pdev **pdev,
+					  uint8_t num_pdevs);
 #endif
 };
 

+ 40 - 3
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -59,13 +59,47 @@ struct vdev_mlme_obj;
 #define STA_PROFILE_SUB_ELEM_ID 0
 #define PER_STA_PROF_MAC_ADDR_START 4
 
+#ifdef WLAN_MLO_MULTI_CHIP
 /*
- * struct mlo_setup_info
- * To store the MLO setup related information
+ * enum MLO_LINK_STATE – MLO link state enums
+ * @MLO_LINK_SETUP_INIT - MLO link SETUP exchange not yet done
+ * @MLO_LINK_SETUP_DONE - MLO link SETUP exchange started
+ * @MLO_LINK_READY - MLO link SETUP done and READY sent
+ * @MLO_LINK_TEARDOWN - MLO teardown done.
  */
+enum MLO_LINK_STATE {
+	MLO_LINK_SETUP_INIT,
+	MLO_LINK_SETUP_DONE,
+	MLO_LINK_READY,
+	MLO_LINK_TEARDOWN
+};
+
+/**
+ * struct mlo_setup_info: MLO setup status per link
+ * @ml_grp_id: Unique id for ML grouping of Pdevs/links
+ * @tot_socs: Total number of soc participating in ML group
+ * @num_soc: Number of soc ready or probed
+ * @tot_links: Total links in ML group
+ * @num_links: Number of links probed in ML group
+ * @pdev_list[MAX_MLO_LINKS]: pdev pointers belonging to this group
+ * @state[MAX_MLO_LINKS]: MLO link state
+ * @state_lock: lock to protect access to link state
+ */
+#define MAX_MLO_LINKS 6
 struct mlo_setup_info {
+	uint8_t ml_grp_id;
+	uint8_t tot_socs;
+	uint8_t num_soc;
+	uint8_t tot_links;
+	uint8_t num_links;
+	struct wlan_objmgr_pdev *pdev_list[MAX_MLO_LINKS];
+	enum MLO_LINK_STATE state[MAX_MLO_LINKS];
+	qdf_spinlock_t state_lock;
 };
 
+#define MAX_MLO_GROUP 1
+#endif
+
 /*
  * struct mlo_mgr_context - MLO manager context
  * @ml_dev_list_lock: ML DEV list lock
@@ -94,7 +128,9 @@ struct mlo_mgr_context {
 	qdf_list_t ml_dev_list;
 	qdf_bitmap(mlo_peer_id_bmap, MAX_MLO_PEER_ID);
 	uint16_t max_mlo_peer_id;
-	struct mlo_setup_info info;
+#ifdef WLAN_MLO_MULTI_CHIP
+	struct mlo_setup_info setup_info;
+#endif
 	struct mlo_mlme_ext_ops *mlme_ops;
 	struct ctxt_switch_mgr *msgq_ctx;
 	bool mlo_is_force_primary_umac;
@@ -344,4 +380,5 @@ struct mlo_mlme_ext_ops {
 						  uint8_t link_ix);
 	void (*mlo_mlme_ext_deauth)(struct wlan_objmgr_peer *peer);
 };
+
 #endif

+ 69 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_setup.h

@@ -0,0 +1,69 @@
+/* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains MLO manager public file containing setup/teardown functionality
+ */
+
+#ifdef WLAN_MLO_MULTI_CHIP
+/**
+ * mlo_setup_update_total_socs() - API to update total socs for mlo
+ * @tot_socs: Total socs
+ *
+ * Return: None.
+ */
+void mlo_setup_update_total_socs(uint8_t tot_socs);
+
+/**
+ * mlo_setup_update_num_links() - API to update num links in soc for mlo
+ * @soc_id: soc id of SoC corresponding to num_link
+ * @num_links: Number of links in that soc
+ *
+ * Return: None.
+ */
+void mlo_setup_update_num_links(uint8_t soc_id, uint8_t num_links);
+
+/**
+ * mlo_setup_update_soc_ready() - API to notify when FW init done
+ * @soc_id: soc id of SoC ready
+ *
+ * Return: None.
+ */
+void mlo_setup_update_soc_ready(uint8_t soc_id);
+
+/**
+ * mlo_setup_link_ready() - API to notify link ready
+ * @pdev: Pointer to pdev object
+ *
+ * Return: None.
+ */
+void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * mlo_link_setup_complete() - API to notify setup complete
+ * @pdev: Pointer to pdev object
+ *
+ * Return: None.
+ */
+void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * mlo_link_teardown_complete() - API to notify teardown complete
+ * @pdev: Pointer to pdev object
+ *
+ * Return: None.
+ */
+void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev);
+#endif

+ 142 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_setup.c

@@ -0,0 +1,142 @@
+/* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains MLO manager ap related functionality
+ */
+#include "wlan_mlo_mgr_cmn.h"
+#include "wlan_mlo_mgr_main.h"
+#ifdef WLAN_MLO_MULTI_CHIP
+#include "wlan_lmac_if_def.h"
+#endif
+
+#ifdef WLAN_MLO_MULTI_CHIP
+void mlo_setup_update_total_socs(uint8_t tot_socs)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx)
+		return;
+
+	mlo_ctx->setup_info.tot_socs = tot_socs;
+}
+
+qdf_export_symbol(mlo_setup_update_total_socs);
+
+void mlo_setup_update_num_links(uint8_t soc_id, uint8_t num_links)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx)
+		return;
+
+	mlo_ctx->setup_info.tot_links += num_links;
+}
+
+qdf_export_symbol(mlo_setup_update_num_links);
+
+void mlo_setup_update_soc_ready(uint8_t soc_id)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx)
+		return;
+
+	mlo_ctx->setup_info.num_soc++;
+}
+
+qdf_export_symbol(mlo_setup_update_soc_ready);
+
+void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+	uint8_t link_idx;
+
+	if (!mlo_ctx)
+		return;
+
+	link_idx = mlo_ctx->setup_info.num_links;
+	/* TODO: Get reference to PDEV */
+	mlo_ctx->setup_info.pdev_list[link_idx] = pdev;
+	mlo_ctx->setup_info.state[link_idx] = MLO_LINK_SETUP_INIT;
+	mlo_ctx->setup_info.num_links++;
+
+	if (mlo_ctx->setup_info.num_links == mlo_ctx->setup_info.tot_links &&
+	    mlo_ctx->setup_info.num_soc == mlo_ctx->setup_info.tot_socs) {
+		struct wlan_objmgr_psoc *psoc;
+		struct wlan_lmac_if_tx_ops *tx_ops;
+
+		psoc = wlan_pdev_get_psoc(pdev);
+		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
+		/* Trigger MLO setup */
+		if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) {
+			tx_ops->mops.target_if_mlo_setup_req(
+					mlo_ctx->setup_info.pdev_list,
+					mlo_ctx->setup_info.num_links,
+					mlo_ctx->setup_info.ml_grp_id);
+		}
+	}
+}
+
+qdf_export_symbol(mlo_setup_link_ready);
+
+void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+	uint8_t link_idx;
+
+	if (!mlo_ctx)
+		return;
+
+	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
+		if (mlo_ctx->setup_info.pdev_list[link_idx] == pdev) {
+			mlo_ctx->setup_info.state[link_idx] =
+							MLO_LINK_SETUP_DONE;
+			break;
+		}
+
+	for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++)
+		if (mlo_ctx->setup_info.state[link_idx] == MLO_LINK_SETUP_DONE)
+			continue;
+		else
+			break;
+
+	if (link_idx == mlo_ctx->setup_info.tot_links) {
+		struct wlan_objmgr_psoc *psoc;
+		struct wlan_lmac_if_tx_ops *tx_ops;
+
+		psoc = wlan_pdev_get_psoc(pdev);
+		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
+		/* Trigger MLO ready */
+		if (tx_ops && tx_ops->mops.target_if_mlo_ready) {
+			tx_ops->mops.target_if_mlo_ready(
+					mlo_ctx->setup_info.pdev_list,
+					mlo_ctx->setup_info.num_links);
+		}
+	}
+}
+
+qdf_export_symbol(mlo_link_setup_complete);
+
+void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx)
+		return;
+}
+
+qdf_export_symbol(mlo_link_teardown_complete);
+#endif /*WLAN_MLO_MULTI_CHIP*/