Browse Source

qcacmn: MLO manager init/de-init

-Add MLO manager global init/de-init
-Add MLO manager vdev create/destroy handlers

Change-Id: I376a52ef7cae28616965bda72b5803155159eb6f
CRs-Fixed: 2947789
Sandeep Puligilla 4 years ago
parent
commit
a64d8a0dbe

+ 9 - 1
init_deinit/dispatcher/src/dispatcher_init_deinit.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021 The Linux Foundation. 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
@@ -81,6 +81,7 @@
 #include <wlan_dcs_init_deinit_api.h>
 #endif
 #include <wlan_if_mgr_main.h>
+#include <wlan_mlo_mgr_main.h>
 #include <wlan_gpio_api.h>
 
 /**
@@ -923,6 +924,9 @@ QDF_STATUS dispatcher_init(void)
 	if (QDF_STATUS_SUCCESS != wlan_objmgr_global_obj_init())
 		goto out;
 
+	if (QDF_STATUS_SUCCESS != wlan_mlo_mgr_init())
+		goto mgmt_mlo_mgr_fail;
+
 	if (QDF_STATUS_SUCCESS != wlan_mgmt_txrx_init())
 		goto mgmt_txrx_init_fail;
 
@@ -1055,6 +1059,8 @@ ucfg_scan_init_fail:
 	wlan_mgmt_txrx_deinit();
 mgmt_txrx_init_fail:
 	wlan_objmgr_global_obj_deinit();
+mgmt_mlo_mgr_fail:
+	wlan_mlo_mgr_deinit();
 
 out:
 	return QDF_STATUS_E_FAILURE;
@@ -1116,6 +1122,8 @@ QDF_STATUS dispatcher_deinit(void)
 
 	QDF_BUG(QDF_STATUS_SUCCESS == wlan_mgmt_txrx_deinit());
 
+	QDF_BUG(QDF_STATUS_SUCCESS == wlan_mlo_mgr_deinit());
+
 	QDF_BUG(QDF_STATUS_SUCCESS == wlan_objmgr_global_obj_deinit());
 
 	return QDF_STATUS_SUCCESS;

+ 2 - 0
umac/cmn_services/inc/wlan_cmn.h

@@ -284,6 +284,7 @@
  * @WLAN_IOT_SIM_COMP:            IOT Simulation component
  * @WLAN_UMAC_COMP_IF_MGR:        Interface manager component
  * @WLAN_UMAC_COMP_GPIO:          GPIO Configuration
+ * @WLAN_UMAC_COMP_MLO_MGR:       MLO manager
  * @WLAN_UMAC_COMP_ID_MAX:        Maximum components in UMAC
  *
  * This id is static.
@@ -330,6 +331,7 @@ enum wlan_umac_comp_id {
 	WLAN_IOT_SIM_COMP                 = 37,
 	WLAN_UMAC_COMP_IF_MGR             = 38,
 	WLAN_UMAC_COMP_GPIO               = 39,
+	WLAN_UMAC_COMP_MLO_MGR            = 40,
 	WLAN_UMAC_COMP_ID_MAX,
 };
 

+ 2 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h

@@ -281,6 +281,7 @@ typedef void (*wlan_objmgr_peer_status_handler)(
  * @WLAN_OSIF_TDLS_ID:          TDLS operations in OS IF
  * @WLAN_OSIF_CM_ID:            Connection manager osif reference id
  * @WLAN_TXRX_STREAMS_ID:       Preferred TX & RX streams operations
+ * @WLAN_MLO_MGR_ID:            MLO manager reference id
  * @WLAN_REF_ID_MAX:            Max id used to generate ref count tracking array
  */
  /* New value added to the enum must also be reflected in function
@@ -378,6 +379,7 @@ typedef enum {
 	WLAN_OSIF_TDLS_ID     = 87,
 	WLAN_OSIF_CM_ID       = 88,
 	WLAN_TXRX_STREAMS_ID  = 89,
+	WLAN_MLO_MGR_ID = 90,
 	WLAN_REF_ID_MAX,
 } wlan_objmgr_ref_dbgid;
 

+ 39 - 9
umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h

@@ -252,6 +252,7 @@
  * @legacy_osif:    Legacy os_if private member
  * @macaddr[]:      MAC address
  * @mataddr[]:      MAT address
+ * @mldaddr[]:      MLD address
  */
 struct wlan_vdev_create_params {
 	enum QDF_OPMODE opmode;
@@ -260,6 +261,7 @@ struct wlan_vdev_create_params {
 	void *legacy_osif;
 	uint8_t macaddr[QDF_MAC_ADDR_SIZE];
 	uint8_t mataddr[QDF_MAC_ADDR_SIZE];
+	uint8_t mldaddr[QDF_MAC_ADDR_SIZE];
 };
 
 /**
@@ -304,15 +306,7 @@ struct wlan_channel {
  * @vdev_op_flags:      Operation flags
  * @mataddr[]:          MAT address
  * @macaddr[]:          VDEV self MAC address
- * @ssid[]:             SSID
- * @ssid_len:           SSID length
- * @nss:                Num. Spatial streams
- * @tx_chainmask:       Tx Chainmask
- * @rx_chainmask:       Rx Chainmask
- * @tx_power:           Tx power
- * @max_rate:           MAX rate
- * @tx_mgmt_rate:       TX Mgmt. Rate
- * @per_band_mgmt_rate: Per-band TX Mgmt. Rate
+ * @mldaddr[]:          MLD address
  */
 struct wlan_objmgr_vdev_mlme {
 	enum QDF_OPMODE vdev_opmode;
@@ -327,6 +321,7 @@ struct wlan_objmgr_vdev_mlme {
 	uint32_t vdev_op_flags;
 	uint8_t  mataddr[QDF_MAC_ADDR_SIZE];
 	uint8_t  macaddr[QDF_MAC_ADDR_SIZE];
+	uint8_t  mldaddr[QDF_MAC_ADDR_SIZE];
 };
 
 /**
@@ -755,6 +750,41 @@ static inline void wlan_vdev_mlme_set_mataddr(struct wlan_objmgr_vdev *vdev,
 	WLAN_ADDR_COPY(vdev->vdev_mlme.mataddr, mataddr);
 }
 
+/**
+ * wlan_vdev_mlme_get_mldaddr() - get vdev mldaddr
+ * @vdev: VDEV object
+ *
+ * API to get MLD address from vdev object
+ *
+ * Caller need to acquire lock with wlan_vdev_obj_lock()
+ *
+ * Return:
+ * @macaddr: MAC address
+ */
+static inline uint8_t *wlan_vdev_mlme_get_mldaddr(struct wlan_objmgr_vdev *vdev)
+{
+	/* This API is invoked with lock acquired, do not add log prints */
+	return vdev->vdev_mlme.mldaddr;
+}
+
+/**
+ * wlan_vdev_mlme_set_mldaddr() - set vdev mldaddr
+ * @vdev: VDEV object
+ * @mldaddr: MLD address
+ *
+ * API to set MLD addr in vdev object
+ *
+ * Caller need to acquire lock with wlan_vdev_obj_lock()
+ *
+ * Return: void
+ */
+static inline void wlan_vdev_mlme_set_mldaddr(struct wlan_objmgr_vdev *vdev,
+					uint8_t *mldaddr)
+{
+	/* This API is invoked with lock acquired, do not add log prints */
+	WLAN_ADDR_COPY(vdev->vdev_mlme.mldaddr, mldaddr);
+}
+
 /**
  * wlan_vdev_mlme_get_mataddr() - get mataddr
  * @vdev: VDEV object

+ 2 - 0
umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c

@@ -208,6 +208,8 @@ struct wlan_objmgr_vdev *wlan_objmgr_vdev_obj_create(
 	wlan_vdev_mlme_set_macaddr(vdev, params->macaddr);
 	/* set MAT address */
 	wlan_vdev_mlme_set_mataddr(vdev, params->mataddr);
+	/* set MLD address */
+	wlan_vdev_mlme_set_mldaddr(vdev, params->mldaddr);
 	/* Set create flags */
 	vdev->vdev_objmgr.c_flags = params->flags;
 	/* store os-specific pointer */

+ 18 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h

@@ -22,6 +22,7 @@
 
 #include <qdf_types.h>
 #include <qdf_trace.h>
+#include "wlan_mlo_mgr_public_structs.h"
 
 #define mlo_alert(format, args...) \
 		QDF_TRACE_FATAL(QDF_MODULE_ID_MLO, format, ## args)
@@ -52,4 +53,21 @@
 
 #define mlo_nofl_debug(format, args...) \
 		QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_MLO, format, ## args)
+/**
+ * mlo_get_link_information() - get partner link information
+ * @mld_addr : MLD address
+ * @info: partner link information
+ *
+ * Return: QDF_STATUS
+ */
+void mlo_get_link_information(struct qdf_mac_addr *mld_addr,
+			      struct mlo_link_info *info);
+/**
+ * is_mlo_all_links_up() - check all the link status in a MLO device
+ * @ml_dev: ML device context
+ *
+ * Return: QDF_STATUS
+ */
+void is_mlo_all_links_up(struct wlan_mlo_dev_context *ml_dev);
+
 #endif

+ 218 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_main.h

@@ -20,4 +20,222 @@
 #ifndef _WLAN_MLO_MGR_MAIN_H_
 #define _WLAN_MLO_MGR_MAIN_H_
 
+#include <qdf_atomic.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_mlo_mgr_public_structs.h>
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * wlan_mlo_mgr_init() - Initialize the MLO data structures
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlo_mgr_init(void);
+
+/**
+ * wlan_mlo_mgr_deinit() - De-init the MLO data structures
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlo_mgr_deinit(void);
+
+/**
+ * wlan_mlo_mgr_vdev_created_notification() - mlo mgr vdev create handler
+ * @vdev: vdev object
+ * @arg_list: Argument list
+ *
+ * This function is called as part of vdev creation. This will initialize
+ * the MLO dev context if the interface type is ML.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
+						  void *arg_list);
+
+/**
+ * wlan_mlo_mgr_vdev_destroyed_notification() - mlo mgr vdev delete handler
+ * @vdev: vdev object
+ * @arg_list: Argument list
+ *
+ * This function is called as part of vdev delete. This will de-initialize
+ * the MLO dev context if the interface type is ML.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
+						    void *arg_list);
+
+#ifdef WLAN_MLO_USE_SPINLOCK
+/**
+ * ml_link_lock_create - Create MLO link mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * Creates mutex/spinlock
+ *
+ * Return: void
+ */
+static inline
+void ml_link_lock_create(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spinlock_create(&mlo_ctx->ml_dev_list_lock);
+}
+
+/**
+ * ml_link_lock_destroy - Destroy ml link mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * Destroy mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+ml_link_lock_destroy(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spinlock_destroy(&mlo_ctx->ml_dev_list_lock);
+}
+
+/**
+ * ml_link_lock_acquire - acquire ml link mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_link_lock_acquire(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spin_lock_bh(&mlo_ctx->ml_dev_list_lock);
+}
+
+/**
+ * ml_link_lock_release - release MLO dev mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_link_lock_release(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spin_unlock_bh(&mlo_ctx->ml_dev_list_lock);
+}
+
+/**
+ * mlo_dev_lock_create - Create MLO device mutex/spinlock
+ * @mldev:  ML device context
+ *
+ * Creates mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+mlo_dev_lock_create(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_spinlock_create(&mldev->mlo_dev_lock);
+}
+
+/**
+ * mlo_dev_lock_destroy - Destroy CM SM mutex/spinlock
+ * @mldev:  ML device context
+ *
+ * Destroy mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+mlo_dev_lock_destroy(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_spinlock_destroy(&mldev->mlo_dev_lock);
+}
+
+/**
+ * mlo_dev_lock_acquire - acquire CM SM mutex/spinlock
+ * @mldev:  ML device context
+ *
+ * acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void mlo_dev_lock_acquire(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_spin_lock_bh(&mldev->mlo_dev_lock);
+}
+
+/**
+ * mlo_dev_lock_release - release MLO dev mutex/spinlock
+ * @mldev:  ML device context
+ *
+ * release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void mlo_dev_lock_release(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_spin_unlock_bh(&mldev->mlo_dev_lock);
+}
+#else
+static inline
+void ml_link_lock_create(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_create(&mlo_ctx->ml_dev_list_lock);
+}
+
+static inline void
+ml_link_lock_destroy(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_destroy(&mlo_ctx->ml_dev_list_lock);
+}
+
+static inline
+void ml_link_lock_acquire(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_acquire(&mlo_ctx->ml_dev_list_lock);
+}
+
+static inline
+void ml_link_lock_release(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_release(&mlo_ctx->ml_dev_list_lock);
+}
+
+static inline
+void mlo_dev_lock_create(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_mutex_create(&mldev->mlo_dev_lock);
+}
+
+static inline
+void mlo_dev_lock_destroy(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_mutex_destroy(&mldev->mlo_dev_lock);
+}
+
+static inline void mlo_dev_lock_acquire(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_mutex_acquire(&mldev->mlo_dev_lock);
+}
+
+static inline void mlo_dev_lock_release(struct wlan_mlo_dev_context *mldev)
+{
+	qdf_mutex_release(&mldev->mlo_dev_lock);
+}
+#endif /* WLAN_MLO_USE_SPINLOCK */
+
+#else
+static inline QDF_STATUS wlan_mlo_mgr_init(void)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS wlan_mlo_mgr_deinit(void)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #endif

+ 6 - 1
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -44,11 +44,16 @@ struct mlo_setup_info {
 
 /*
  * struct mlo_mgr_context - MLO manager context
+ * @ml_dev_list_lock: ML device list lock
  * @context: Array of MLO device context
  * @info: MLO setup info
  */
 struct mlo_mgr_context {
+#ifdef WLAN_MLO_USE_SPINLOCK
 	qdf_spinlock_t ml_dev_list_lock;
+#else
+	qdf_mutex_t ml_dev_list_lock;
+#endif
 	qdf_list_t ml_dev_list;
 	struct mlo_setup_info info;
 };
@@ -116,7 +121,7 @@ struct wlan_mlo_dev_context {
 	uint16_t wlan_vdev_count;
 	struct wlan_mlo_peer_list mlo_peer;
 	uint16_t wlan_max_mlo_peer_count;
-#ifdef WLAN_USE_SPINLOCK
+#ifdef WLAN_MLO_USE_SPINLOCK
 	qdf_spinlock_t mlo_dev_lock;
 #else
 	qdf_mutex_t mlo_dev_lock;

+ 12 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c

@@ -17,4 +17,16 @@
 /*
  * DOC: contains MLO manager ap related functionality
  */
+#include "wlan_mlo_mgr_cmn.h"
 
+void mlo_get_link_information(struct qdf_mac_addr *mld_addr,
+			      struct mlo_link_info *info)
+{
+/* Pass the partner link information*/
+}
+
+void is_mlo_all_links_up(struct wlan_mlo_dev_context *mldev)
+{
+/* Loop through all the vdev's part of the ML device*/
+/* STA: Loop through all the associated vdev status. */
+}

+ 286 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_main.c

@@ -17,3 +17,289 @@
 /*
  * DOC: contains MLO manager init/deinit api's
  */
+
+#include "wlan_mlo_mgr_main.h"
+#include "qdf_types.h"
+#include "wlan_cmn.h"
+#include <wlan_objmgr_global_obj.h>
+#include "wlan_mlo_mgr_cmn.h"
+
+/* Global MLO Manager context pointer */
+struct mlo_mgr_context *g_mlo_mgr_ctx;
+
+static void mlo_global_ctx_deinit(void)
+{
+	if (qdf_list_empty(&g_mlo_mgr_ctx->ml_dev_list))
+		mlo_err("ML dev list is not empty");
+
+	ml_link_lock_destroy(g_mlo_mgr_ctx);
+	qdf_list_destroy(&g_mlo_mgr_ctx->ml_dev_list);
+
+	qdf_mem_free(g_mlo_mgr_ctx);
+	g_mlo_mgr_ctx = NULL;
+}
+
+static void mlo_global_ctx_init(void)
+{
+	struct mlo_mgr_context *mlo_mgr_ctx;
+
+	/* If it is already created, ignore */
+	if (g_mlo_mgr_ctx) {
+		mlo_err("Global object is already created");
+		return;
+	}
+
+	/* Allocation of memory for Global object */
+	mlo_mgr_ctx = (struct mlo_mgr_context *)
+			qdf_mem_malloc(sizeof(*mlo_mgr_ctx));
+	if (!mlo_mgr_ctx)
+		return;
+	g_mlo_mgr_ctx = mlo_mgr_ctx;
+
+	qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV);
+	ml_link_lock_create(mlo_mgr_ctx);
+}
+
+QDF_STATUS wlan_mlo_mgr_init(void)
+{
+	QDF_STATUS status;
+
+	mlo_global_ctx_init();
+
+	status = wlan_objmgr_register_vdev_create_handler(
+		WLAN_UMAC_COMP_MLO_MGR,
+		wlan_mlo_mgr_vdev_created_notification, NULL);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlo_err("Failed to register vdev create handler");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_MLO_MGR,
+		wlan_mlo_mgr_vdev_destroyed_notification, NULL);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mlo_debug("MLO vdev create and delete handler registered with objmgr");
+		return QDF_STATUS_SUCCESS;
+	}
+	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_MLO_MGR,
+				wlan_mlo_mgr_vdev_created_notification, NULL);
+
+	return status;
+}
+
+QDF_STATUS wlan_mlo_mgr_deinit(void)
+{
+	QDF_STATUS status;
+
+	if (!g_mlo_mgr_ctx) {
+		mlo_err("MLO global object is not allocated");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlo_global_ctx_deinit();
+
+	status = wlan_objmgr_unregister_vdev_create_handler(
+		WLAN_UMAC_COMP_MLO_MGR,
+		wlan_mlo_mgr_vdev_created_notification, NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		mlo_err("Failed to unregister vdev create handler");
+
+	status = wlan_objmgr_unregister_vdev_destroy_handler(
+			WLAN_UMAC_COMP_MLO_MGR,
+			wlan_mlo_mgr_vdev_destroyed_notification, NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		mlo_err("Failed to unregister vdev delete handler");
+
+	return status;
+}
+
+static inline struct wlan_mlo_dev_context *mlo_list_peek_head(
+					qdf_list_t *ml_list)
+{
+	struct wlan_mlo_dev_context *mld_ctx;
+	qdf_list_node_t *ml_node = NULL;
+
+	/* This API is invoked with lock acquired, do not add log prints */
+	if (qdf_list_peek_front(ml_list, &ml_node) != QDF_STATUS_SUCCESS)
+		return NULL;
+
+	mld_ctx = qdf_container_of(ml_node, struct wlan_mlo_dev_context,
+				   node);
+
+	return mld_ctx;
+}
+
+static inline
+struct wlan_mlo_dev_context *mlo_get_next_mld_ctx(qdf_list_t *ml_list,
+					struct wlan_mlo_dev_context *mld_cur)
+{
+	struct wlan_mlo_dev_context *mld_next;
+	qdf_list_node_t *node = &mld_cur->node;
+	qdf_list_node_t *next_node = NULL;
+
+	/* This API is invoked with lock acquired, do not add log prints */
+	if (!node)
+		return NULL;
+
+	if (qdf_list_peek_next(ml_list, node, &next_node) !=
+						QDF_STATUS_SUCCESS)
+		return NULL;
+
+	mld_next = qdf_container_of(next_node, struct wlan_mlo_dev_context,
+				    node);
+	return mld_next;
+}
+
+static inline struct wlan_mlo_dev_context
+*wlan_mlo_get_mld_ctx_by_mldaddr(struct qdf_mac_addr *mldaddr)
+{
+	struct wlan_mlo_dev_context *mld_cur;
+	struct wlan_mlo_dev_context *mld_next;
+	qdf_list_t *ml_list;
+
+	ml_link_lock_acquire(g_mlo_mgr_ctx);
+	ml_list = &g_mlo_mgr_ctx->ml_dev_list;
+	/* Get first mld context */
+	mld_cur = mlo_list_peek_head(ml_list);
+	/**
+	 * Iterate through ml list, till ml mldaddr matches with
+	 * entry of list
+	 */
+	while (mld_cur) {
+		if (QDF_IS_STATUS_SUCCESS(WLAN_ADDR_EQ(&mld_cur->mld_addr,
+					  mldaddr))) {
+			ml_link_lock_release(g_mlo_mgr_ctx);
+			return mld_cur;
+		}
+		/* get next mld node */
+		mld_next = mlo_get_next_mld_ctx(ml_list, mld_cur);
+		mld_cur = mld_next;
+	}
+	ml_link_lock_release(g_mlo_mgr_ctx);
+
+	return NULL;
+}
+
+static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct qdf_mac_addr *mld_addr;
+	struct mlo_mgr_context *g_mlo_ctx = g_mlo_mgr_ctx;
+	uint8_t id = 0;
+
+	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
+	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
+	if (ml_dev) {
+		mlo_dev_lock_acquire(ml_dev);
+		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
+			if (ml_dev->wlan_vdev_list[id]) {
+				id++;
+				continue;
+			}
+			ml_dev->wlan_vdev_list[id] = vdev;
+			ml_dev->wlan_vdev_count++;
+			vdev->mlo_dev_ctx = ml_dev;
+			break;
+		}
+		mlo_dev_lock_release(ml_dev);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	/* Create a new ML dev context */
+	ml_dev = qdf_mem_malloc(sizeof(*ml_dev));
+	if (!ml_dev) {
+		mlo_err("Failed to allocate memory for ML dev");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_copy_macaddr(&ml_dev->mld_addr, mld_addr);
+	ml_dev->wlan_vdev_list[0] = vdev;
+	ml_dev->wlan_vdev_count++;
+	vdev->mlo_dev_ctx = ml_dev;
+	mlo_dev_lock_create(ml_dev);
+	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
+		ml_dev->sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_sta));
+		if (!ml_dev->sta_ctx)
+			return QDF_STATUS_E_NOMEM;
+	} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
+		ml_dev->ap_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_ap));
+		if (!ml_dev->ap_ctx)
+			return QDF_STATUS_E_NOMEM;
+	}
+
+	ml_link_lock_acquire(g_mlo_ctx);
+	if (qdf_list_size(&g_mlo_ctx->ml_dev_list) < WLAN_UMAC_MLO_MAX_DEV)
+		qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node);
+	ml_link_lock_release(g_mlo_ctx);
+
+	return status;
+}
+
+static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct qdf_mac_addr *mld_addr;
+	struct mlo_mgr_context *g_mlo_ctx = g_mlo_mgr_ctx;
+	uint8_t id = 0;
+
+	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
+	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
+	if (!ml_dev) {
+		mlo_err("Failed to get MLD dev context");
+		return QDF_STATUS_SUCCESS;
+	} else {
+		mlo_debug("deleting vdev from MLD device ctx");
+		mlo_dev_lock_acquire(ml_dev);
+		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
+			if (ml_dev->wlan_vdev_list[id] == vdev) {
+				ml_dev->wlan_vdev_list[id] = NULL;
+				ml_dev->wlan_vdev_count--;
+				vdev->mlo_dev_ctx = NULL;
+				break;
+			}
+			id++;
+		}
+		mlo_dev_lock_release(ml_dev);
+	}
+	ml_link_lock_acquire(g_mlo_ctx);
+	if (!ml_dev->wlan_vdev_count) {
+		qdf_list_remove_node(&g_mlo_mgr_ctx->ml_dev_list,
+			     &ml_dev->node);
+		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE)
+			qdf_mem_free(ml_dev->sta_ctx);
+		else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
+			qdf_mem_free(ml_dev->ap_ctx);
+		mlo_dev_lock_destroy(ml_dev);
+		qdf_mem_free(ml_dev);
+	}
+	ml_link_lock_release(g_mlo_ctx);
+	return status;
+}
+
+QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
+						  void *arg_list)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!wlan_vdev_mlme_get_mldaddr(vdev))
+		/* It's not a ML interface*/
+		return QDF_STATUS_SUCCESS;
+	status = mlo_dev_ctx_init(vdev);
+
+	return status;
+}
+
+QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
+						    void *arg_list)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!wlan_vdev_mlme_get_mldaddr(vdev))
+		/* It's not a ML interface*/
+		return QDF_STATUS_SUCCESS;
+
+	status = mlo_dev_ctx_deinit(vdev);
+
+	return status;
+}