Browse Source

qcacmn: MLO peer implementation

This change adds MLO support to Peer.
It implements,
1) MLO peer list management
2) AID allocation
3) MLO Peer creation/deletion
4) Notifying partner links on peer creation/deletion/assoc

Change-Id: Ie1b675dccdf0de1d79f6f32d9255cf3cca53fdf2
CRs-Fixed: 2967057
Srinivas Pitla 4 năm trước cách đây
mục cha
commit
7469335fa4

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

@@ -72,6 +72,9 @@
 /* Max vdev_id */
 #define WLAN_UMAC_VDEV_ID_MAX 0xFF
 
+/* TODO: MAX AID */
+#define WLAN_UMAC_MAX_AID 2048
+
 /* Invalid pdev_id */
 #define WLAN_INVALID_PDEV_ID 0xFFFFFFFF
 

+ 97 - 1
umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h

@@ -95,6 +95,9 @@
 /* node is a local mesh peer */
 #define WLAN_PEER_F_LOCAL_MESH_PEER                 0x80000000
 
+/* MLO enabled peer */
+#define WLAN_PEER_FEXT_MLO                          0x00000001
+
 /**
  * enum wlan_peer_state  - peer state
  * @WLAN_INIT_STATE:       Default state
@@ -121,6 +124,7 @@ enum wlan_peer_state {
  * struct wlan_objmgr_peer_mlme - mlme common data of peer
  * @peer_capinfo:    protocol cap info
  * @peer_flags:      PEER OP flags
+ * @peer_ext_flags:  PEER OP ext flags
  * @peer_type:       Type of PEER, (STA/AP/etc.)
  * @phymode:         phy mode of station
  * @max_rate:        Max Rate supported
@@ -132,6 +136,7 @@ enum wlan_peer_state {
 struct wlan_objmgr_peer_mlme {
 	uint32_t peer_capinfo;
 	uint32_t peer_flags;
+	uint32_t peer_ext_flags;
 	enum wlan_peer_type peer_type;
 	enum wlan_phymode phymode;
 	uint32_t max_rate;
@@ -191,7 +196,7 @@ struct wlan_objmgr_peer {
 	WLAN_OBJ_STATE obj_state;
 	qdf_spinlock_t peer_lock;
 #ifdef WLAN_FEATURE_11BE_MLO
-	struct mlo_peer_ctx *mlo_peer_ctx;
+	struct wlan_mlo_peer_context *mlo_peer_ctx;
 	uint8_t mldaddr[QDF_MAC_ADDR_SIZE];
 #endif
 };
@@ -840,6 +845,35 @@ static inline enum wlan_phymode wlan_peer_get_phymode(
 	return peer->peer_mlme.phymode;
 }
 
+/**
+ * wlan_peer_set_rssi() - set RSSI
+ * @peer: PEER object
+ * @rssi: RSSI
+ *
+ * API to set rssi
+ *
+ * Return: void
+ */
+static inline void wlan_peer_set_rssi(struct wlan_objmgr_peer *peer,
+				      int8_t rssi)
+{
+	peer->peer_mlme.rssi = rssi;
+}
+
+/**
+ * wlan_peer_get_rssi() - get RSSI
+ * @peer: PEER object
+ *
+ * API to get RSSI
+ *
+ * Return:
+ * @rssi: RSSI of PEER
+ */
+static inline int8_t wlan_peer_get_rssi(
+				struct wlan_objmgr_peer *peer)
+{
+	return peer->peer_mlme.rssi;
+}
 
 /**
  * wlan_peer_set_macaddr() - set mac addr
@@ -951,6 +985,51 @@ static inline uint8_t wlan_peer_mlme_flag_get(struct wlan_objmgr_peer *peer,
 	return (peer->peer_mlme.peer_flags & flag) ? 1 : 0;
 }
 
+/**
+ * wlan_peer_mlme_flag_ext_set() - mlme ext flag set
+ * @peer: PEER object
+ * @flag: ext flag to be set
+ *
+ * API to set ext flag in peer
+ *
+ * Return: void
+ */
+static inline void wlan_peer_mlme_flag_ext_set(struct wlan_objmgr_peer *peer,
+					       uint32_t flag)
+{
+	peer->peer_mlme.peer_ext_flags |= flag;
+}
+
+/**
+ * wlan_peer_mlme_flag_clear() - mlme ext flag clear
+ * @peer: PEER object
+ * @flag: ext flag to be cleared
+ *
+ * API to clear ext flag in peer
+ *
+ * Return: void
+ */
+static inline void wlan_peer_mlme_flag_ext_clear(struct wlan_objmgr_peer *peer,
+						 uint32_t flag)
+{
+	peer->peer_mlme.peer_ext_flags &= ~flag;
+}
+
+/**
+ * wlan_peer_mlme_flag_ext_get() - mlme ext flag get
+ * @peer: PEER object
+ * @flag: ext flag to be checked
+ *
+ * API to know, whether particular ext flag is set in peer
+ *
+ * Return: 1 (for set) or 0 (for not set)
+ */
+static inline uint8_t wlan_peer_mlme_flag_ext_get(struct wlan_objmgr_peer *peer,
+						  uint32_t flag)
+{
+	return (peer->peer_mlme.peer_ext_flags & flag) ? 1 : 0;
+}
+
 /**
  * wlan_peer_mlme_set_state() - peer mlme state
  * @peer: PEER object
@@ -1173,6 +1252,23 @@ static inline struct wlan_objmgr_psoc *wlan_peer_get_psoc(
 	return psoc;
 }
 
+/**
+ * wlan_peer_get_psoc_id() - get psoc id
+ * @peer: PEER object
+ *
+ * API to get peer's psoc id
+ *
+ * Return: @psoc_id: psoc id
+ */
+static inline uint8_t wlan_peer_get_psoc_id(struct wlan_objmgr_peer *peer)
+{
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_peer_get_psoc(peer);
+
+	return wlan_psoc_get_id(psoc);
+}
+
 /*
  * wlan_peer_get_pdev_id() - get pdev id
  * @peer: peer object pointer

+ 17 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h

@@ -667,6 +667,23 @@ static inline struct wlan_objmgr_psoc *wlan_vdev_get_psoc(
 	return psoc;
 }
 
+/**
+ * wlan_vdev_get_psoc_id() - get psoc id
+ * @vdev: VDEV object
+ *
+ * API to get VDEV's psoc id
+ *
+ * Return: @psoc_id: psoc id
+ */
+static inline uint8_t wlan_vdev_get_psoc_id(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+
+	return wlan_psoc_get_id(psoc);
+}
+
 /**
  * wlan_vdev_mlme_set_opmode() - set vdev opmode
  * @vdev: VDEV object

+ 57 - 0
umac/mlme/include/wlan_vdev_mlme.h

@@ -349,14 +349,28 @@ struct vdev_mlme_mgmt_generic {
 	bool special_vdev_mode;
 };
 
+/*
+ * struct wlan_vdev_aid_mgr – AID manager
+ * @aid_bitmap: AID bitmap array
+ * @max_aid: Max allowed AID
+ * @ref_cnt:  to share AID across VDEVs for MBSSID
+ */
+struct wlan_vdev_aid_mgr {
+	qdf_bitmap(aid_bitmap, WLAN_UMAC_MAX_AID);
+	uint16_t max_aid;
+	qdf_atomic_t ref_cnt;
+};
+
 /**
  * struct vdev_mlme_mgmt_ap - ap specific vdev mlme mgmt cfg
  * @hidden_ssid: flag to indicate whether it is hidden ssid
  * @cac_duration_ms: cac duration in millseconds
+ * @aid_mgr: AID bitmap mgr
  */
 struct vdev_mlme_mgmt_ap {
 	bool hidden_ssid;
 	uint32_t cac_duration_ms;
+	struct wlan_vdev_aid_mgr *aid_mgr;
 };
 
 /**
@@ -1100,4 +1114,47 @@ static inline uint16_t wlan_vdev_mlme_get_he_mcs_12_13_map(
 	return 0;
 }
 #endif
+
+/**
+ * wlan_vdev_mlme_set_aid_mgr() - set aid mgr
+ * @vdev: VDEV object
+ * @aid_mgr: AID mgr
+ *
+ * API to set AID mgr in VDEV MLME cmpt object
+ *
+ * Return: void
+ */
+static inline void wlan_vdev_mlme_set_aid_mgr(
+				struct wlan_objmgr_vdev *vdev,
+				struct wlan_vdev_aid_mgr *aid_mgr)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme)
+		return;
+
+	vdev_mlme->mgmt.ap.aid_mgr = aid_mgr;
+}
+
+/**
+ * wlan_vdev_mlme_get_aid_mgr() - get aid mgr
+ * @vdev: VDEV object
+ *
+ * API to get AID mgr in VDEV MLME cmpt object
+ *
+ * Return: aid_mgr
+ */
+static inline struct wlan_vdev_aid_mgr *wlan_vdev_mlme_get_aid_mgr(
+				struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme)
+		return NULL;
+
+	return vdev_mlme->mgmt.ap.aid_mgr;
+}
+
 #endif

+ 11 - 0
umac/mlme/vdev_mgr/dispatcher/inc/wlan_vdev_mlme_api.h

@@ -159,6 +159,17 @@ QDF_STATUS wlan_vdev_mlme_is_csa_restart(struct wlan_objmgr_vdev *vdev);
  */
 QDF_STATUS wlan_vdev_is_going_down(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * wlan_vdev_is_peer_create_allowed() - Checks whether PEER can be created
+ * @vdev: Object manager VDEV object
+ *
+ * API to check the VDEV MLME SM state to allow PEER association
+ *
+ * Return: SUCCESS: if peer create can be allowed
+ *         FAILURE: otherwise failure
+ */
+QDF_STATUS wlan_vdev_is_peer_create_allowed(struct wlan_objmgr_vdev *vdev);
+
 /**
  * wlan_vdev_is_restart_progress() - Checks VDEV restart is in progress
  * @vdev: Object manager VDEV object

+ 16 - 0
umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mlme_api.c

@@ -224,6 +224,22 @@ QDF_STATUS wlan_vdev_is_going_down(struct wlan_objmgr_vdev *vdev)
 	return QDF_STATUS_E_FAILURE;
 }
 
+QDF_STATUS wlan_vdev_is_peer_create_allowed(struct wlan_objmgr_vdev *vdev)
+{
+	enum wlan_vdev_state state;
+	enum wlan_vdev_state substate;
+
+	state = wlan_vdev_mlme_get_state(vdev);
+	substate = wlan_vdev_mlme_get_substate(vdev);
+	if (!((state == WLAN_VDEV_S_INIT) ||
+	     (state == WLAN_VDEV_S_STOP) ||
+	     ((state == WLAN_VDEV_S_SUSPEND) &&
+	      (substate == WLAN_VDEV_SS_SUSPEND_SUSPEND_DOWN))))
+		return QDF_STATUS_SUCCESS;
+
+	return QDF_STATUS_E_FAILURE;
+}
+
 QDF_STATUS wlan_vdev_is_restart_progress(struct wlan_objmgr_vdev *vdev)
 {
 	enum wlan_vdev_state state;

+ 222 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_ap.h

@@ -82,4 +82,226 @@ void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev);
  * Return: None
  */
 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev);
+/**
+ * wlan_vdev_aid_mgr_init() - VDEV AID mgr init
+ * @max_aid: max AID
+ *
+ * This function is called as part of vdev/MLO DEV initialization.
+ * This will allocate aid mgr structure for a VDEV
+ *
+ * Return: aid_mgr
+ */
+struct wlan_vdev_aid_mgr *wlan_vdev_aid_mgr_init(uint16_t max_aid);
+
+/**
+ * wlan_vdev_aid_mgr_free() - VDEV AID mgr free
+ * @aid_mgr: AID mgr
+ *
+ * This function frees the aid mgr of the VDEV
+ *
+ * Return: void
+ */
+void wlan_vdev_aid_mgr_free(struct wlan_vdev_aid_mgr *aid_mgr);
+
+/**
+ * wlan_mlo_vdev_aid_mgr_init() - MLO AID mgr init
+ * @ml_dev: MLO DEV context
+ *
+ * This function allocate AID space for all associated VDEVs of MLD
+ *
+ * Return: SUCCESS if allocated successfully
+ */
+QDF_STATUS wlan_mlo_vdev_aid_mgr_init(struct wlan_mlo_dev_context *ml_dev);
+
+/**
+ * wlan_mlo_vdev_aid_mgr_deinit() - MLO AID mgr free
+ * @ml_dev: MLO DEV context
+ *
+ * This function frees AID space for all associated VDEVs of MLD
+ *
+ * Return: void
+ */
+void wlan_mlo_vdev_aid_mgr_deinit(struct wlan_mlo_dev_context *ml_dev);
+
+/**
+ * wlan_mlo_vdev_alloc_aid_mgr() - Allocate AID space for a VDEV
+ * @ml_dev: MLO DEV context
+ * @vdev: VDEV
+ *
+ * This function allocates AID space for an associated VDEV of MLD
+ *
+ * Return: SUCCESS if allocated successfully
+ */
+QDF_STATUS wlan_mlo_vdev_alloc_aid_mgr(struct wlan_mlo_dev_context *ml_dev,
+				       struct wlan_objmgr_vdev *vdev);
+
+/**
+ * wlan_mlo_vdev_free_aid_mgr() - Free AID space for a VDEV
+ * @ml_dev: MLO DEV context
+ * @vdev: VDEV
+ *
+ * This function frees AID space for an associated VDEV of MLD
+ *
+ * Return: SUCCESS if freed successfully
+ */
+QDF_STATUS wlan_mlo_vdev_free_aid_mgr(struct wlan_mlo_dev_context *ml_dev,
+				      struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlo_peer_allocate_aid() - Allocate AID for MLO peer
+ * @ml_dev: MLO DEV context
+ * @ml_peer: MLO peer object
+ *
+ * This function allocates AID for an MLO peer
+ *
+ * Return: SUCCESS if allocated successfully
+ */
+QDF_STATUS mlo_peer_allocate_aid(
+		struct wlan_mlo_dev_context *ml_dev,
+		struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * mlo_get_aid() - Allocate AID for a associated station
+ * @vdev: VDEV
+ *
+ * This function allocates AID for an associated station of MLD
+ *
+ * Return: AID
+ */
+uint16_t mlo_get_aid(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlo_free_aid() - Frees AID for a station
+ * @vdev: VDEV
+ * @assoc_id: Assoc ID
+ *
+ * This function frees AID for an associated station of MLD
+ *
+ * Return: SUCCESS if freed
+ */
+QDF_STATUS mlo_free_aid(struct wlan_objmgr_vdev *vdev, uint16_t assoc_id);
+
+/**
+ * mlme_get_aid() - Allocate AID for a non-MLD station
+ * @vdev: VDEV
+ *
+ * This function allocates AID for an associated NON-MLD station of MLD
+ *
+ * Return: AID
+ */
+uint16_t mlme_get_aid(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * wlan_mlo_peer_free_aid() - Free assoc id
+ * @ml_aid_mgr: MLO AID mgr
+ * @link_ix: Link index
+ * @assoc_id: Assoc id to be freed
+ *
+ * This function frees assoc id, resets bit in all bitmaps
+ *
+ * Return: SUCCESS,if it freed
+ */
+QDF_STATUS wlan_mlo_peer_free_aid(
+		struct wlan_ml_vdev_aid_mgr *ml_aid_mgr,
+		uint8_t link_ix,
+		uint16_t assoc_id);
+
+/**
+ * wlan_mlme_peer_free_aid() - Free link assoc id
+ * @vdev_aid_mgr: VDEV AID mgr
+ * @no_lock: lock needed for the operation
+ * @assoc_id: Assoc id to be freed
+ *
+ * This function frees assoc id of a specific VDEV
+ *
+ * Return: void
+ */
+void wlan_mlme_peer_free_aid(
+		struct wlan_vdev_aid_mgr *vdev_aid_mgr,
+		bool no_lock, uint16_t assoc_id);
+
+/**
+ * mlo_peer_free_aid() - public API to free AID
+ * @ml_dev: MLO DEV context
+ * @ml_peer: MLO peer object
+ *
+ * This function invokes low level API to free assoc id
+ *
+ * Return: SUCCESS, if it freed
+ */
+QDF_STATUS mlo_peer_free_aid(struct wlan_mlo_dev_context *ml_dev,
+			     struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * mlme_free_aid() - public API to free link assoc id
+ * @vdev: VDEV object
+ * @assoc_id: Assoc id to be freed
+ *
+ * This function invokes low level API to free assoc id of a specific VDEV
+ *
+ * Return: void
+ */
+void mlme_free_aid(struct wlan_objmgr_vdev *vdev, uint16_t assoc_id);
+
+/**
+ * mlo_ap_ml_peerid_alloc() - public API to allocate MLO peer id
+ *
+ * This function allocates MLO peer ID
+ *
+ * Return: mlo_peer_id on success,
+	 MLO_INVALID_PEER_ID on failure
+ */
+uint16_t mlo_ap_ml_peerid_alloc(void);
+
+/**
+ * mlo_ap_ml_peerid_free() - public API to free MLO peer id
+ * @ml_peer_id: ML peer id
+ *
+ * This function frees MLO peer ID
+ *
+ * Return: void
+ */
+void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id);
+
+#define ML_PRIMARY_UMAC_ID_INVAL 0xff
+/**
+ * mlo_peer_assign_primary_umac() - Assign Primary UMAC
+ * @ml_peer: MLO peer object
+ * @peer_entry: Link peer entry
+ *
+ * This function assigns primary UMAC flag in peer entry
+ *
+ * Return: SUCCESS,if it allocated
+ */
+void mlo_peer_assign_primary_umac(
+		struct wlan_mlo_peer_context *ml_peer,
+		struct wlan_mlo_link_peer_entry *peer_entry);
+
+/**
+ * mlo_peer_allocate_primary_umac() - Allocate Primary UMAC
+ * @ml_dev: MLO DEV context
+ * @ml_peer: MLO peer object
+ * @link_vdev: link vdev array
+ *
+ * This function allocates primary UMAC for a MLO peer
+ *
+ * Return: SUCCESS,if it allocated
+ */
+QDF_STATUS mlo_peer_allocate_primary_umac(
+		struct wlan_mlo_dev_context *ml_dev,
+		struct wlan_mlo_peer_context *ml_peer,
+		struct wlan_objmgr_vdev *link_vdevs[]);
+
+/**
+ * mlo_peer_free_primary_umac() - Free Primary UMAC
+ * @ml_dev: MLO DEV context
+ * @ml_peer: MLO peer object
+ *
+ * This function frees primary UMAC for a MLO peer
+ *
+ * Return: SUCCESS,if it is freed
+ */
+QDF_STATUS mlo_peer_free_primary_umac(
+		struct wlan_mlo_dev_context *ml_dev,
+		struct wlan_mlo_peer_context *ml_peer);
 #endif

+ 20 - 1
umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h

@@ -172,7 +172,7 @@ QDF_STATUS mlo_mlme_create_link_vdev(struct wlan_objmgr_vdev *vdev,
  */
 void mlo_mlme_peer_create(struct wlan_objmgr_vdev *vdev,
 			  struct wlan_mlo_peer_context *ml_peer,
-			  struct qdf_mac_addr addr,
+			  struct qdf_mac_addr *addr,
 			  qdf_nbuf_t frm_buf);
 
 /**
@@ -198,4 +198,23 @@ void mlo_mlme_peer_assoc_fail(struct wlan_objmgr_peer *peer);
  * Return: void
  */
 void mlo_mlme_peer_delete(struct wlan_objmgr_peer *peer);
+
+/**
+ * mlo_mlme_peer_assoc_resp() - Initiate sending of Assoc response
+ * @peer: Object manager peer
+ *
+ * Return: void
+ */
+void mlo_mlme_peer_assoc_resp(struct wlan_objmgr_peer *peer);
+
+/**
+ * mlo_get_link_vdev_ix() - Get index of link VDEV in MLD
+ * @ml_dev: ML device context
+ * @vdev: VDEV object
+ *
+ * Return: link index
+ */
+
+uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *mldev,
+			     struct wlan_objmgr_vdev *vdev);
 #endif

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

@@ -179,6 +179,231 @@ void mlo_dev_lock_release(struct wlan_mlo_dev_context *mldev)
 {
 	qdf_spin_unlock_bh(&mldev->mlo_dev_lock);
 }
+
+/**
+ * ml_aid_lock_create - Create MLO aid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * Creates mutex/spinlock
+ *
+ * Return: void
+ */
+static inline
+void ml_aid_lock_create(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spinlock_create(&mlo_ctx->aid_lock);
+}
+
+/**
+ * ml_aid_lock_destroy - Destroy ml aid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * Destroy mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+ml_aid_lock_destroy(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spinlock_destroy(&mlo_ctx->aid_lock);
+}
+
+/**
+ * ml_aid_lock_acquire - acquire ml aid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_aid_lock_acquire(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spin_lock_bh(&mlo_ctx->aid_lock);
+}
+
+/**
+ * ml_aid_lock_release - release MLO aid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_aid_lock_release(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spin_unlock_bh(&mlo_ctx->aid_lock);
+}
+
+/**
+ * ml_peerid_lock_create - Create MLO peer mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * Creates mutex/spinlock
+ *
+ * Return: void
+ */
+static inline
+void ml_peerid_lock_create(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spinlock_create(&mlo_ctx->ml_peerid_lock);
+}
+
+/**
+ * ml_peerid_lock_destroy - Destroy ml peerid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * Destroy mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+ml_peerid_lock_destroy(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spinlock_destroy(&mlo_ctx->ml_peerid_lock);
+}
+
+/**
+ * ml_peerid_lock_acquire - acquire ml peerid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_peerid_lock_acquire(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spin_lock_bh(&mlo_ctx->ml_peerid_lock);
+}
+
+/**
+ * ml_peerid_lock_release - release MLO peerid mutex/spinlock
+ * @mlo_ctx:  MLO manager global context
+ *
+ * release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_peerid_lock_release(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_spin_unlock_bh(&mlo_ctx->ml_peerid_lock);
+}
+
+/**
+ * mlo_peer_lock_create - Create MLO peer mutex/spinlock
+ * @mlpeer:  ML peer
+ *
+ * Creates mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+mlo_peer_lock_create(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_spinlock_create(&mlpeer->mlo_peer_lock);
+}
+
+/**
+ * mlo_peer_lock_destroy - Destroy MLO peer mutex/spinlock
+ * @mlpeer:  ML peer
+ *
+ * Destroy mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+mlo_peer_lock_destroy(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_spinlock_destroy(&mlpeer->mlo_peer_lock);
+}
+
+/**
+ * mlo_peer_lock_acquire - acquire mlo peer mutex/spinlock
+ * @mlpeer:  MLO peer context
+ *
+ * acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void mlo_peer_lock_acquire(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_spin_lock_bh(&mlpeer->mlo_peer_lock);
+}
+
+/**
+ * mlo_peer_lock_release - release MLO peer mutex/spinlock
+ * @mlpeer:  MLO peer context
+ *
+ * release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void mlo_peer_lock_release(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_spin_unlock_bh(&mlpeer->mlo_peer_lock);
+}
+
+/**
+ * ml_peerlist_lock_create - Create MLO peer list mutex/spinlock
+ * @ml_peerlist:  ML peer list context
+ *
+ * Creates mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+ml_peerlist_lock_create(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_spinlock_create(&ml_peerlist->peer_list_lock);
+}
+
+/**
+ * ml_peerlist_lock_destroy - Destroy MLO peer list mutex/spinlock
+ * @ml_peerlist:  ML peer list context
+ *
+ * Destroy mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+ml_peerlist_lock_destroy(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_spinlock_destroy(&ml_peerlist->peer_list_lock);
+}
+
+/**
+ * ml_peerlist_lock_acquire - acquire ML peer list mutex/spinlock
+ * @ml_peerlist:  ML peer list context
+ *
+ * acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_peerlist_lock_acquire(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_spin_lock_bh(&ml_peerlist->peer_list_lock);
+}
+
+/**
+ * ml_peerlist_lock_release - release ML peer list mutex/spinlock
+ * @ml_peerlist:  ML peer list context
+ *
+ * release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void ml_peerlist_lock_release(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_spin_unlock_bh(&ml_peerlist->peer_list_lock);
+}
+
 #else
 static inline
 void ml_link_lock_create(struct mlo_mgr_context *mlo_ctx)
@@ -225,6 +450,102 @@ static inline void mlo_dev_lock_release(struct wlan_mlo_dev_context *mldev)
 {
 	qdf_mutex_release(&mldev->mlo_dev_lock);
 }
+
+static inline
+void ml_aid_lock_create(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_create(&mlo_ctx->aid_lock);
+}
+
+static inline void
+ml_aid_lock_destroy(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_destroy(&mlo_ctx->aid_lock);
+}
+
+static inline
+void ml_aid_lock_acquire(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_acquire(&mlo_ctx->aid_lock);
+}
+
+static inline
+void ml_aid_lock_release(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_release(&mlo_ctx->aid_lock);
+}
+
+static inline
+void ml_peerid_lock_create(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_create(&mlo_ctx->ml_peerid_lock);
+}
+
+static inline void
+ml_peerid_lock_destroy(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_destroy(&mlo_ctx->ml_peerid_lock);
+}
+
+static inline
+void ml_peerid_lock_acquire(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_acquire(&mlo_ctx->ml_peerid_lock);
+}
+
+static inline
+void ml_peerid_lock_release(struct mlo_mgr_context *mlo_ctx)
+{
+	qdf_mutex_release(&mlo_ctx->ml_peerid_lock);
+}
+
+static inline void
+mlo_peer_lock_create(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_mutex_create(&mlpeer->mlo_peer_lock);
+}
+
+static inline void
+mlo_peer_lock_destroy(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_mutex_destroy(&mlpeer->mlo_peer_lock);
+}
+
+static inline
+void mlo_peer_lock_acquire(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_mutex_acquire(&mlpeer->mlo_peer_lock);
+}
+
+static inline
+void mlo_peer_lock_release(struct wlan_mlo_peer_context *mlpeer)
+{
+	qdf_mutex_release(&mlpeer->mlo_peer_lock);
+}
+
+static inline void
+ml_peerlist_lock_create(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_mutex_create(&ml_peerlist->peer_list_lock);
+}
+
+static inline void
+ml_peerlist_lock_destroy(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_mutex_destroy(&ml_peerlist->peer_list_lock);
+}
+
+static inline
+void ml_peerlist_lock_acquire(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_mutex_acquire(&ml_peerlist->peer_list_lock);
+}
+
+static inline
+void ml_peerlist_lock_release(struct wlan_mlo_peer_list *ml_peerlist)
+{
+	qdf_mutex_release(&ml_peerlist->peer_list_lock);
+}
 #endif /* WLAN_MLO_USE_SPINLOCK */
 
 #else

+ 134 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_msgq.h

@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 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
+ * 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 msgq structure definitions
+ */
+
+#ifndef __MLO_MGR_MSGQ_H
+#define __MLO_MGR_MSGQ_H
+
+/*
+ * struct ctxt_switch_mgr - MLO context switch manager
+ * @ctxt_mgr_timer: Timer to process messages
+ * @msgq_list: list to hold pending messages
+ * @ctxt_lock: Lock to have atomic context
+ * @timer_started: indicates whether timer is running
+ * @max_messages_procd: Max messages can be stored
+ */
+struct ctxt_switch_mgr {
+	qdf_timer_t ctxt_mgr_timer;
+	qdf_list_t msgq_list;
+	qdf_spinlock_t ctxt_lock;
+	bool timer_started;
+	uint16_t max_messages_procd;
+};
+
+/*
+ * enum mlo_msg_type – MLO partner peer message type
+ * @MLO_PEER_CREATE:   Partner peer create
+ * @MLO_PEER_ASSOC:    Partner peer ASSOC
+ * @MLO_PEER_ASSOC_FAIL:  Partner peer ASSOC failure
+ * @MLO_PEER_DISCONNECT:  Partner peer Disconnect
+ */
+enum mlo_msg_type {
+	MLO_PEER_CREATE,
+	MLO_PEER_ASSOC,
+	MLO_PEER_ASSOC_FAIL,
+	MLO_PEER_DISCONNECT,
+};
+
+/*
+ * struct peer_create_notif_s - MLO partner peer create notification
+ * @vdev_link: Link VDEV
+ * @ml_peer: ML peer to attached
+ * @addr: Link MAC address
+ * @frm_buf: Assoc request buffer
+ */
+struct peer_create_notif_s {
+	struct wlan_objmgr_vdev *vdev_link;
+	struct wlan_mlo_peer_context *ml_peer;
+	struct qdf_mac_addr addr;
+	qdf_nbuf_t frm_buf;
+};
+
+/*
+ * struct peer_assoc_notify_s - MLO partner peer assoc notification
+ * @peer: Link peer on which Peer ASSOC to be sent
+ */
+struct peer_assoc_notify_s {
+	struct wlan_objmgr_peer *peer;
+};
+
+/*
+ * struct peer_assoc_fail_notify_s - MLO partner peer assoc fail notification
+ * @peer: Link peer on which Peer assoc resp failure to be sent
+ */
+struct peer_assoc_fail_notify_s {
+	struct wlan_objmgr_peer *peer;
+};
+
+/*
+ * struct peer_discon_notify_s - MLO partner peer disconnect notification
+ * @peer: Link peer on which Peer disconnect to be sent
+ */
+struct peer_discon_notify_s {
+	struct wlan_objmgr_peer *peer;
+};
+
+/*
+ * union msg_payload - MLO message payload
+ * @peer_create: peer create notification structure
+ * @peer_assoc: peer assoc notification structure
+ * @peer_assoc_fail: peer assoc fail notification structure
+ * @peer_disconn: peer disconnect notification structure
+ */
+union msg_payload {
+	struct peer_create_notif_s peer_create;
+	struct peer_assoc_notify_s peer_assoc;
+	struct peer_assoc_fail_notify_s peer_assoc_fail;
+	struct peer_discon_notify_s peer_disconn;
+};
+
+#define MLO_MAX_MSGQ_SIZE 256
+/*
+ * struct mlo_ctxt_switch_msg_s - MLO ctxt switch message
+ * @type: peer create notification structure
+ * @peer_assoc: peer assoc notification structure
+ * @peer_assoc_fail: peer assoc fail notification structure
+ * @peer_disconn: peer disconnect notification structure
+ */
+struct mlo_ctxt_switch_msg_s {
+	qdf_list_node_t node;
+	enum mlo_msg_type type;
+	struct wlan_mlo_dev_context *ml_dev;
+	union msg_payload m;
+};
+
+/**
+ * mlo_msgq_post() - Posts message to defer context
+ * @type: msg tupe
+ * @ml_dev: MLO dev context
+ * @payload: msg buf
+ *
+ * This function post message to defer conext queue for defer processing
+ *
+ * Return: SUCCESS if msg is posted
+ */
+QDF_STATUS mlo_msgq_post(enum mlo_msg_type type,
+			 struct wlan_mlo_dev_context *ml_dev,
+			 void *payload);
+#endif

+ 304 - 4
umac/mlo_mgr/inc/wlan_mlo_mgr_peer.h

@@ -20,6 +20,7 @@
 #ifndef _WLAN_MLO_MGR_PEER_H_
 #define _WLAN_MLO_MGR_PEER_H_
 
+#include "wlan_objmgr_peer_obj.h"
 /**
  * mlo_peer_create - Initiatiate peer create on secondary link(s)
  * by posting a message
@@ -98,12 +99,311 @@ void mlo_peer_delete(struct wlan_objmgr_peer *peer);
 bool is_mlo_all_peer_links_deleted(void);
 
 /**
- * mlo_get_aid - Get the association ID
+ * wlan_mlo_peer_is_disconnect_progress() - MLO peer is in disconnect progress
+ * @ml_peer: MLO peer
  *
- * @vdev: pointer to vdev
+ * This function checks whether MLO Peer is in disconnect progress
+ *
+ * Return: SUCCESS if MLO Peer is in disconnect progress
+ */
+QDF_STATUS wlan_mlo_peer_is_disconnect_progress(
+					struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * wlan_mlo_peer_is_assoc_done() - MLO peer is Assoc complete
+ * @ml_peer: MLO peer
+ *
+ * This function checks whether MLO Peer's Assoc is completed
+ *
+ * Return: SUCCESS if MLO Peer Assoc is completed
+ */
+QDF_STATUS wlan_mlo_peer_is_assoc_done(struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * wlan_mlo_peer_get_assoc_peer() - get assoc peer
+ * @ml_peer: MLO peer
+ *
+ * This function returns assoc peer of MLO peer
+ *
+ * Return: assoc peer, if it is found, otherwise NULL
+ */
+struct wlan_objmgr_peer *wlan_mlo_peer_get_assoc_peer(
+					struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * wlan_mlo_partner_peer_assoc_post() - Notify partner peer assoc
+ * @peer: Link peer
+ *
+ * This function notifies link peers to send peer assoc command to FW
+ *
+ * Return: void
+ */
+void wlan_mlo_partner_peer_assoc_post(struct wlan_objmgr_peer *assoc_peer);
+
+/**
+ * wlan_mlo_partner_peer_create_failed_notify() - Notify peer creation fail
+ * @ml_peer: MLO peer
+ *
+ * This function notifies about link peer creation failure
+ *
+ * Return: void
+ */
+void wlan_mlo_partner_peer_create_failed_notify(
+					struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * wlan_mlo_partner_peer_disconnect_notify() - Notify peer disconnect
+ * @peer: Link peer
+ *
+ * This function notifies about disconnect is being initilated on link peer
+ *
+ * Return: void
+ */
+void wlan_mlo_partner_peer_disconnect_notify(struct wlan_objmgr_peer *src_peer);
+
+/**
+ * wlan_mlo_peer_create() - MLO peer create
+ * @vdev: Link VDEV
+ * @link_peer: Link peer
+ * @ml_info: ML links info
+ * @frm_buf: Assoc req buffer
+ * @aid: AID, if already allocated
+ *
+ * This function creates MLO peer and notifies other partner VDEVs to create
+ * link peers
+ *
+ * Return: SUCCESS, if MLO peer is successfully created
+ */
+QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev,
+				struct wlan_objmgr_peer *link_peer,
+				struct mlo_partner_info *ml_info,
+				qdf_nbuf_t frm_buf,
+				uint16_t aid);
+
+/**
+ * mlo_peer_free() - Free MLO peer
+ * @ml_peer: MLO peer
+ *
+ * This function frees MLO peer and resets MLO peer associations
+ * Note, this API is ref count protected, it should be always invoked
+ * from wlan_mlo_peer_release_ref()
+ *
+ * Return: void
+ */
+void mlo_peer_free(struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * wlan_mlo_peer_get_ref() - Get ref of MLO peer
+ * @ml_peer: MLO peer
+ *
+ * This function gets ref of MLO peer
+ *
+ * Return: void
+ */
+static inline void wlan_mlo_peer_get_ref(struct wlan_mlo_peer_context *ml_peer)
+{
+	qdf_atomic_inc(&ml_peer->ref_cnt);
+}
+
+/**
+ * wlan_mlo_peer_release_ref() - Release ref of MLO peer
+ * @ml_peer: MLO peer
+ *
+ * This function releases ref of MLO peer, if ref is 0, invokes MLO peer free
+ *
+ * Return: void
+ */
+static inline void wlan_mlo_peer_release_ref(
+					struct wlan_mlo_peer_context *ml_peer)
+{
+	if (qdf_atomic_dec_and_test(&ml_peer->ref_cnt))
+		mlo_peer_free(ml_peer);
+}
+
+/**
+ * wlan_mlo_link_peer_attach() - MLO link peer attach
+ * @ml_peer: MLO peer
+ * @peer: Link peer
+ *
+ * This function attaches link peer to MLO peer
+ *
+ * Return: SUCCESS, if peer is successfully attached to MLO peer
+ */
+QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer,
+				     struct wlan_objmgr_peer *peer);
+
+/**
+ * wlan_mlo_link_peer_delete() - MLO link peer delete
+ * @peer: Link peer
+ *
+ * This function detaches link peer from MLO peer, if this peer is last link
+ * peer, then MLO peer gets deleted
+ *
+ * Return: SUCCESS, if peer is detached from MLO peer
+ */
+QDF_STATUS wlan_mlo_link_peer_delete(struct wlan_objmgr_peer *peer);
+
+/**
+ ** APIs to operations on ML peer object
+ */
+typedef QDF_STATUS (*wlan_mlo_op_handler)(struct wlan_mlo_dev_context *ml_dev,
+				    void *ml_peer,
+				    void *arg);
+
+/**
+ * wlan_mlo_iterate_ml_peerlist() - iterate through all ml peer objects
+ * @ml_dev: MLO DEV object
+ * @handler: the handler will be called for each ml peer
+ *            the handler should be implemented to perform required operation
+ * @arg:     agruments passed by caller
+ *
+ * API to be used for performing the operations on all ML PEER objects
+ *
+ * Return: SUCCESS/FAILURE
+ */
+QDF_STATUS wlan_mlo_iterate_ml_peerlist(struct wlan_mlo_dev_context *ml_dev,
+					wlan_mlo_op_handler handler,
+					void *arg);
+
+/**
+ * wlan_mlo_get_mlpeer_by_linkmac() - find ML peer by Link MAC address
+ * @ml_dev: MLO DEV object
+ * @link_mac:  Link peer MAC address
+ *
+ * API to get ML peer using link MAC address
+ *
+ * Return: ML peer object, if it is found
+ *         otherwise, returns NULL
+ */
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_linkmac(
+				struct wlan_mlo_dev_context *ml_dev,
+				struct qdf_mac_addr *link_mac);
+
+/**
+ * wlan_mlo_get_mlpeer_by_aid() - find ML peer by AID
+ * @ml_dev: MLO DEV object
+ * @aid:  AID
+ *
+ * API to get ML peer using AID
+ *
+ * Return: ML peer object, if it is found
+ *         otherwise, returns NULL
+ */
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_aid(
+				struct wlan_mlo_dev_context *ml_dev,
+				uint16_t assoc_id);
+
+/**
+ * wlan_mlo_get_mlpeer_by_ml_peerid() - find ML peer by ML peer id
+ * @ml_dev: MLO DEV object
+ * @ml_peerid:  ML Peer ID
+ *
+ * API to get ML peer using ML peer id
+ *
+ * Return: ML peer object, if it is found
+ *         otherwise, returns NULL
+ */
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_ml_peerid(
+				struct wlan_mlo_dev_context *ml_dev,
+				uint16_t ml_peerid);
+
+/**
+ * wlan_mlo_get_mlpeer() - find ML peer by MLD MAC address
+ * @ml_dev: MLO DEV object
+ * @ml_addr: MLO MAC address
+ *
+ * API to get ML peer using MLO MAC address
+ *
+ * Return: ML peer object, if it is found
+ *         otherwise, returns NULL
+ */
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer(
+				struct wlan_mlo_dev_context *ml_dev,
+				struct qdf_mac_addr *ml_addr);
+
+/**
+ * mlo_dev_mlpeer_attach() - Add ML PEER to ML peer list
+ * @ml_dev: MLO DEV object
+ * @ml_peer: ML peer
+ *
+ * API to attach ML PEER to MLD PEER table
  *
- * Return: AID value
+ * Return: SUCCESS, if it attached successfully
+ *         otherwise, returns FAILURE
  */
-uint8_t mlo_get_aid(struct wlan_objmgr_vdev *vdev);
+QDF_STATUS mlo_dev_mlpeer_attach(struct wlan_mlo_dev_context *ml_dev,
+				 struct wlan_mlo_peer_context *ml_peer);
 
+/**
+ * mlo_dev_mlpeer_detach() - Delete ML PEER from ML peer list
+ * @ml_dev: MLO DEV object
+ * @ml_peer: ML peer
+ *
+ * API to detach ML PEER from MLD PEER table
+ *
+ * Return: SUCCESS, if it detached successfully
+ *         otherwise, returns FAILURE
+ */
+QDF_STATUS mlo_dev_mlpeer_detach(struct wlan_mlo_dev_context *ml_dev,
+				 struct wlan_mlo_peer_context *ml_peer);
+
+/**
+ * mlo_dev_mlpeer_list_init() - Initialize ML peer list
+ * @ml_dev: MLO DEV object
+ *
+ * API to initialize MLO peer list
+ *
+ * Return: SUCCESS, if initialized successfully
+ */
+QDF_STATUS mlo_dev_mlpeer_list_init(struct wlan_mlo_dev_context *ml_dev);
+
+/**
+ * mlo_dev_mlpeer_list_deinit() - destroys ML peer list
+ * @ml_dev: MLO DEV object
+ *
+ * API to destroys MLO peer list
+ *
+ * Return: SUCCESS, if initialized successfully
+ */
+QDF_STATUS mlo_dev_mlpeer_list_deinit(struct wlan_mlo_dev_context *ml_dev);
+
+/**
+ * wlan_peer_is_mlo() - check whether peer is MLO link peer
+ * @peer: link peer object
+ *
+ * API to check link peer is part of MLO peer or not
+ *
+ * Return: true if it MLO peer
+ *         false, if it is not MLO peer
+ */
+static inline uint8_t wlan_peer_is_mlo(struct wlan_objmgr_peer *peer)
+{
+	return wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO);
+}
+
+/**
+ * wlan_peer_set_mlo() - Set peer as MLO link peer
+ * @peer: link peer object
+ *
+ * API to set MLO peer flag in link peer is part of MLO peer
+ *
+ * Return: void
+ */
+static inline void wlan_peer_set_mlo(struct wlan_objmgr_peer *peer)
+{
+	return wlan_peer_mlme_flag_ext_set(peer, WLAN_PEER_FEXT_MLO);
+}
+
+/**
+ * wlan_peer_clear_mlo() - clear peer as MLO link peer
+ * @peer: link peer object
+ *
+ * API to clear MLO peer flag in link peer
+ *
+ * Return: void
+ */
+static inline void wlan_peer_clear_mlo(struct wlan_objmgr_peer *peer)
+{
+	return wlan_peer_mlme_flag_ext_clear(peer, WLAN_PEER_FEXT_MLO);
+}
 #endif

+ 68 - 21
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -66,20 +66,48 @@ struct mlo_setup_info {
 
 /*
  * struct mlo_mgr_context - MLO manager context
- * @ml_dev_list_lock: ML device list lock
+ * @ml_dev_list_lock: ML DEV list lock
+ * @aid_lock: AID global lock
+ * @ml_peerid_lock: ML peer ID global lock
  * @context: Array of MLO device context
+ * @mlo_peer_id_bmap: bitmap to allocate MLO Peer ID
+ * @max_mlo_peer_id: Max MLO Peer ID
  * @info: MLO setup info
  * @mlme_ops: MLO MLME callback function pointers
+ * @msgq_ctx: Context switch mgr
+ * @mlo_is_force_primary_umac: Force Primary UMAC enable
+ * @mlo_forced_primary_umac_id: Force Primary UMAC ID
  */
 struct mlo_mgr_context {
 #ifdef WLAN_MLO_USE_SPINLOCK
 	qdf_spinlock_t ml_dev_list_lock;
+	qdf_spinlock_t aid_lock;
+	qdf_spinlock_t ml_peerid_lock;
 #else
 	qdf_mutex_t ml_dev_list_lock;
+	qdf_mutex_t aid_lock;
+	qdf_mutex_t ml_peerid_lock;
 #endif
 	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;
 	struct mlo_mlme_ext_ops *mlme_ops;
+	struct ctxt_switch_mgr *msgq_ctx;
+	bool mlo_is_force_primary_umac;
+	uint8_t mlo_forced_primary_umac_id;
+};
+
+/*
+ * struct wlan_ml_vdev_aid_mgr – ML AID manager
+ * @aid_bitmap: AID bitmap array
+ * @max_aid: Max allowed AID
+ * @aid_mgr[]:  Array of link vdev aid mgr
+ */
+struct wlan_ml_vdev_aid_mgr {
+	qdf_bitmap(aid_bitmap, WLAN_UMAC_MAX_AID);
+	uint16_t max_aid;
+	struct wlan_vdev_aid_mgr *aid_mgr[WLAN_UMAC_MLO_MAX_VDEVS];
 };
 
 /*
@@ -112,9 +140,11 @@ struct wlan_mlo_sta {
 /*
  * struct wlan_mlo_ap - MLO AP related info
  * @num_ml_vdevs: number of vdevs to form MLD
+ * @ml_aid_mgr: ML AID mgr
  */
 struct wlan_mlo_ap {
 	uint8_t num_ml_vdevs;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
 };
 
 /*
@@ -124,7 +154,11 @@ struct wlan_mlo_ap {
  */
 struct wlan_mlo_peer_list {
 	qdf_list_t peer_hash[WLAN_PEER_HASHSIZE];
+#ifdef WLAN_MLO_USE_SPINLOCK
 	qdf_spinlock_t peer_list_lock;
+#else
+	qdf_mutex_t peer_list_lock;
+#endif
 };
 
 /*
@@ -148,7 +182,7 @@ struct wlan_mlo_dev_context {
 	struct qdf_mac_addr mld_addr;
 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
 	uint16_t wlan_vdev_count;
-	struct wlan_mlo_peer_list mlo_peer;
+	struct wlan_mlo_peer_list mlo_peer_list;
 	uint16_t wlan_max_mlo_peer_count;
 #ifdef WLAN_MLO_USE_SPINLOCK
 	qdf_spinlock_t mlo_dev_lock;
@@ -165,53 +199,64 @@ struct wlan_mlo_dev_context {
  * struct wlan_mlo_link_peer_entry – Link peer entry
  * @link_peer: Object manager peer
  * @link_addr: MAC address of link peer
- * @link_index: Link index
+ * @link_ix: Link index
  * @is_primary: sets true if the peer is primary UMAC’s peer
  * @hw_link_id: HW Link id of peer
  */
 struct wlan_mlo_link_peer_entry {
 	struct wlan_objmgr_peer *link_peer;
 	struct qdf_mac_addr link_addr;
-	uint8_t link_index;
+	uint8_t link_ix;
 	bool is_primary;
 	uint8_t hw_link_id;
 };
 
 /*
- * struct mlo_peer_context - MLO peer context
+ * enum mlo_peer_state – MLO peer state
+ * @ML_PEER_CREATED:     Initial state
+ * @ML_PEER_ASSOC_DONE:  ASSOC sent on assoc link
+ * @ML_PEER_DISCONN_INITIATED: Disconnect initiated on one of the links
+ */
+enum mlo_peer_state {
+	ML_PEER_CREATED,
+	ML_PEER_ASSOC_DONE,
+	ML_PEER_DISCONN_INITIATED,
+};
+
+/*
+ * struct wlan_mlo_peer_context - MLO peer context
  *
+ * @peer_node:     peer list node for ml_dev qdf list
  * @peer_list: list of peers on the MLO link
  * @link_peer_cnt: Number of link peers attached
+ * @max_links: Max links for this ML peer
  * @mlo_peer_id: unique ID for the peer
  * @peer_mld_addr: MAC address of MLD link
  * @mlo_ie: MLO IE struct
- * @mlo_peer_lock: lock to access peer structure
+ * @mlo_peer_lock: lock to access peer strucutre
  * @assoc_id: Assoc ID derived by MLO manager
- * @primary_umac_psoc_id: Primary UMAC PSOC id
  * @ref_cnt: Reference counter to avoid use after free
+ * @ml_dev: MLO dev context
+ * @mlpeer_state: MLO peer state
  */
 struct wlan_mlo_peer_context {
-	struct wlan_mlo_link_peer_entry peer_list[MAX_MLO_PEER];
+	qdf_list_node_t peer_node;
+	struct wlan_mlo_link_peer_entry peer_list[MAX_MLO_LINK_PEERS];
 	uint8_t link_peer_cnt;
+	uint8_t max_links;
 	uint32_t mlo_peer_id;
 	struct qdf_mac_addr peer_mld_addr;
 	uint8_t *mlo_ie;
+#ifdef WLAN_MLO_USE_SPINLOCK
 	qdf_spinlock_t mlo_peer_lock;
+#else
+	qdf_mutex_t mlo_peer_lock;
+#endif
 	uint16_t assoc_id;
 	uint8_t primary_umac_psoc_id;
 	qdf_atomic_t ref_cnt;
-};
-
-/*
- * struct wlan_vdev_aid_mgr – AID manager
- * @aid_bitmap: AID bitmap array
- * @max_aid: Max allowed AID
- * @ref_cnt:  to share AID across VDEVs for MBSSID
- */
-struct wlan_vdev_aid_mgr {
-	uint32_t *aid_bitmap;
-	uint16_t max_aid;
-	qdf_atomic_t ref_cnt;
+	struct wlan_mlo_dev_context *ml_dev;
+	enum mlo_peer_state mlpeer_state;
 };
 
 /*
@@ -242,6 +287,7 @@ struct mlo_partner_info {
  * @mlo_mlme_ext_peer_assoc: Callback to initiate peer assoc
  * @mlo_mlme_ext_peer_assoc_fail: Callback to notify peer assoc failure
  * @mlo_mlme_ext_peer_delete: Callback to initiate link peer delete
+ * @mlo_mlme_ext_assoc_resp: Callback to initiate assoc resp
  */
 struct mlo_mlme_ext_ops {
 	QDF_STATUS (*mlo_mlme_ext_validate_conn_req)(
@@ -250,10 +296,11 @@ struct mlo_mlme_ext_ops {
 		    struct vdev_mlme_obj *vdev_mlme, void *ext_data);
 	void (*mlo_mlme_ext_peer_create)(struct wlan_objmgr_vdev *vdev,
 					 struct wlan_mlo_peer_context *ml_peer,
-					 struct qdf_mac_addr addr,
+					 struct qdf_mac_addr *addr,
 					 qdf_nbuf_t frm_buf);
 	void (*mlo_mlme_ext_peer_assoc)(struct wlan_objmgr_peer *peer);
 	void (*mlo_mlme_ext_peer_assoc_fail)(struct wlan_objmgr_peer *peer);
 	void (*mlo_mlme_ext_peer_delete)(struct wlan_objmgr_peer *peer);
+	void (*mlo_mlme_ext_assoc_resp)(struct wlan_objmgr_peer *peer);
 };
 #endif

+ 544 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_aid.c

@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "wlan_mlo_mgr_main.h"
+#include "qdf_types.h"
+#include "wlan_cmn.h"
+#include <include/wlan_vdev_mlme.h>
+#include "wlan_mlo_mgr_ap.h"
+#include "wlan_mlo_mgr_cmn.h"
+
+static void mlo_peer_set_aid_bit(struct wlan_ml_vdev_aid_mgr *ml_aid_mgr,
+				 uint16_t assoc_id_ix)
+{
+	uint16_t ix;
+	struct wlan_vdev_aid_mgr *vdev_aid_mgr;
+
+	/* Mark this bit as AID assigned */
+	for (ix = 0; ix < WLAN_UMAC_MLO_MAX_VDEVS; ix++) {
+		vdev_aid_mgr = ml_aid_mgr->aid_mgr[ix];
+		if (vdev_aid_mgr)
+			qdf_set_bit(assoc_id_ix, vdev_aid_mgr->aid_bitmap);
+	}
+}
+
+static uint16_t wlan_mlo_peer_alloc_aid(
+		struct wlan_ml_vdev_aid_mgr *ml_aid_mgr,
+		bool is_mlo_peer,
+		uint8_t link_ix)
+{
+	uint16_t assoc_id = (uint16_t)-1;
+	uint16_t i, j;
+	struct wlan_vdev_aid_mgr *vdev_aid_mgr;
+	uint16_t first_aid = 0;
+	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_mgr_ctx)
+		return assoc_id;
+
+	if (!is_mlo_peer && link_ix == 0xff)
+		return assoc_id;
+	/* TODO check locking strategy */
+	ml_aid_lock_acquire(mlo_mgr_ctx);
+
+	for (i = 0; i < ml_aid_mgr->max_aid; i++) {
+		if (qdf_test_bit(i, ml_aid_mgr->aid_bitmap))
+			continue;
+
+		if (is_mlo_peer) {
+			for (j = 0; j < WLAN_UMAC_MLO_MAX_VDEVS; j++) {
+				vdev_aid_mgr = ml_aid_mgr->aid_mgr[j];
+				if (vdev_aid_mgr &&
+				    qdf_test_bit(i, vdev_aid_mgr->aid_bitmap))
+					break;
+				/* AID is free */
+				if (j == WLAN_UMAC_MLO_MAX_VDEVS - 1) {
+					assoc_id = i + 1;
+					mlo_peer_set_aid_bit(ml_aid_mgr, i);
+				}
+			}
+
+			if (assoc_id == i + 1) {
+				qdf_set_bit(i, ml_aid_mgr->aid_bitmap);
+				break;
+			}
+		} else {
+			vdev_aid_mgr = ml_aid_mgr->aid_mgr[link_ix];
+			if (vdev_aid_mgr)
+				break;
+
+			if (qdf_test_bit(i, vdev_aid_mgr->aid_bitmap))
+				continue;
+
+			if (!first_aid)
+				first_aid = i + 1;
+
+			for (j = 0; j < WLAN_UMAC_MLO_MAX_VDEVS; j++) {
+				if (j == link_ix)
+					continue;
+
+				vdev_aid_mgr = ml_aid_mgr->aid_mgr[j];
+				if (vdev_aid_mgr &&
+				    qdf_test_bit(i, vdev_aid_mgr->aid_bitmap)) {
+					assoc_id = i + 1;
+					break;
+				}
+			}
+			if (assoc_id == i + 1) {
+				vdev_aid_mgr = ml_aid_mgr->aid_mgr[link_ix];
+				qdf_set_bit(i, vdev_aid_mgr->aid_bitmap);
+				first_aid = 0;
+				break;
+			}
+		}
+	}
+
+	if ((!is_mlo_peer) && first_aid) {
+		vdev_aid_mgr = ml_aid_mgr->aid_mgr[link_ix];
+		qdf_set_bit(first_aid, vdev_aid_mgr->aid_bitmap);
+		assoc_id = first_aid;
+	}
+
+	ml_aid_lock_release(mlo_mgr_ctx);
+
+	return assoc_id;
+}
+
+static uint16_t wlan_mlme_peer_alloc_aid(
+		struct wlan_vdev_aid_mgr *vdev_aid_mgr,
+		bool no_lock)
+{
+	uint16_t assoc_id = (uint16_t)-1;
+	uint16_t i;
+	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_mgr_ctx)
+		return assoc_id;
+
+	if (!no_lock)
+		ml_aid_lock_acquire(mlo_mgr_ctx);
+
+	for (i = 0; i < vdev_aid_mgr->max_aid; i++) {
+		if (qdf_test_bit(i, vdev_aid_mgr->aid_bitmap))
+			continue;
+
+		assoc_id = i + 1;
+		qdf_set_bit(i, vdev_aid_mgr->aid_bitmap);
+	}
+
+	if (!no_lock)
+		ml_aid_lock_release(mlo_mgr_ctx);
+
+	return assoc_id;
+}
+
+QDF_STATUS wlan_mlo_peer_free_aid(
+		struct wlan_ml_vdev_aid_mgr *ml_aid_mgr,
+		uint8_t link_ix,
+		uint16_t assoc_id)
+{
+	uint16_t  j;
+	struct wlan_vdev_aid_mgr *vdev_aid_mgr;
+	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
+	uint16_t assoc_id_ix;
+
+	if (!mlo_mgr_ctx)
+		return QDF_STATUS_E_FAILURE;
+
+	/* TODO check locking strategy */
+	ml_aid_lock_acquire(mlo_mgr_ctx);
+	assoc_id_ix = assoc_id - 1;
+	if (qdf_test_bit(assoc_id_ix, ml_aid_mgr->aid_bitmap)) {
+		qdf_clear_bit(assoc_id_ix, ml_aid_mgr->aid_bitmap);
+		for (j = 0; j < WLAN_UMAC_MLO_MAX_VDEVS; j++) {
+			vdev_aid_mgr = ml_aid_mgr->aid_mgr[j];
+			if (vdev_aid_mgr &&
+			    qdf_test_bit(assoc_id_ix,
+					 vdev_aid_mgr->aid_bitmap)) {
+				qdf_clear_bit(assoc_id_ix,
+					      vdev_aid_mgr->aid_bitmap);
+			}
+		}
+	} else {
+		vdev_aid_mgr = ml_aid_mgr->aid_mgr[link_ix];
+		if (vdev_aid_mgr)
+			qdf_clear_bit(assoc_id_ix, vdev_aid_mgr->aid_bitmap);
+	}
+
+	ml_aid_lock_release(mlo_mgr_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void wlan_mlme_peer_free_aid(
+		struct wlan_vdev_aid_mgr *vdev_aid_mgr,
+		bool no_lock, uint16_t assoc_id)
+{
+	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_mgr_ctx)
+		return;
+
+	if (!no_lock)
+		ml_aid_lock_acquire(mlo_mgr_ctx);
+
+	qdf_clear_bit(assoc_id - 1, vdev_aid_mgr->aid_bitmap);
+
+	if (!no_lock)
+		ml_aid_lock_release(mlo_mgr_ctx);
+}
+
+QDF_STATUS mlo_peer_allocate_aid(
+		struct wlan_mlo_dev_context *ml_dev,
+		struct wlan_mlo_peer_context *ml_peer)
+{
+	uint16_t assoc_id = (uint16_t)-1;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return QDF_STATUS_E_INVAL;
+
+	assoc_id = wlan_mlo_peer_alloc_aid(ml_aid_mgr, true, 0xff);
+	if (assoc_id == (uint16_t)-1)
+		return QDF_STATUS_E_NOENT;
+
+	ml_peer->assoc_id = assoc_id;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS mlo_peer_free_aid(struct wlan_mlo_dev_context *ml_dev,
+			     struct wlan_mlo_peer_context *ml_peer)
+{
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return QDF_STATUS_E_INVAL;
+
+	wlan_mlo_peer_free_aid(ml_aid_mgr, 0xff, ml_peer->assoc_id);
+
+	return status;
+}
+
+uint16_t mlo_get_aid(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	uint16_t assoc_id = (uint16_t)-1;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+
+	ml_dev = vdev->mlo_dev_ctx;
+
+	if (!ml_dev)
+		return assoc_id;
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return assoc_id;
+
+	return wlan_mlo_peer_alloc_aid(ml_aid_mgr, true, 0xff);
+}
+
+QDF_STATUS mlo_free_aid(struct wlan_objmgr_vdev *vdev, uint16_t assoc_id)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+
+	ml_dev = vdev->mlo_dev_ctx;
+
+	if (!ml_dev)
+		return QDF_STATUS_E_INVAL;
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return QDF_STATUS_E_INVAL;
+
+	return wlan_mlo_peer_free_aid(ml_aid_mgr, true, assoc_id);
+}
+
+uint16_t mlme_get_aid(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	uint16_t assoc_id = (uint16_t)-1;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+	struct wlan_vdev_aid_mgr *vdev_aid_mgr;
+	bool no_lock = true;
+	uint8_t link_id;
+
+	ml_dev = vdev->mlo_dev_ctx;
+
+	if (!ml_dev) {
+		vdev_aid_mgr = wlan_vdev_mlme_get_aid_mgr(vdev);
+		if (vdev_aid_mgr) {
+			if (qdf_atomic_read(&vdev_aid_mgr->ref_cnt) > 1)
+				no_lock = false;
+			return wlan_mlme_peer_alloc_aid(vdev_aid_mgr, no_lock);
+		}
+		return assoc_id;
+	}
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return assoc_id;
+
+	link_id = mlo_get_link_vdev_ix(ml_dev, vdev);
+
+	assoc_id = wlan_mlo_peer_alloc_aid(ml_aid_mgr, false, link_id);
+
+	return assoc_id;
+}
+
+void mlme_free_aid(struct wlan_objmgr_vdev *vdev, uint16_t assoc_id)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+	struct wlan_vdev_aid_mgr *vdev_aid_mgr;
+	bool no_lock = true;
+	uint8_t link_id;
+
+	ml_dev = vdev->mlo_dev_ctx;
+
+	if (!ml_dev) {
+		vdev_aid_mgr = wlan_vdev_mlme_get_aid_mgr(vdev);
+		if (vdev_aid_mgr) {
+			if (qdf_atomic_read(&vdev_aid_mgr->ref_cnt) > 1)
+				no_lock = false;
+
+			wlan_mlme_peer_free_aid(vdev_aid_mgr, no_lock,
+						assoc_id);
+		}
+		return;
+	}
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return;
+
+	link_id = mlo_get_link_vdev_ix(ml_dev, vdev);
+
+	wlan_mlo_peer_free_aid(ml_aid_mgr, link_id, assoc_id);
+}
+
+struct wlan_vdev_aid_mgr *wlan_vdev_aid_mgr_init(uint16_t max_aid)
+{
+	struct wlan_vdev_aid_mgr *aid_mgr;
+
+	aid_mgr = qdf_mem_malloc(sizeof(struct wlan_vdev_aid_mgr));
+	if (!aid_mgr)
+		return NULL;
+
+	aid_mgr->max_aid = max_aid;
+	qdf_atomic_init(&aid_mgr->ref_cnt);
+	/* Take reference before returning */
+	qdf_atomic_inc(&aid_mgr->ref_cnt);
+
+	return aid_mgr;
+}
+
+void wlan_vdev_aid_mgr_free(struct wlan_vdev_aid_mgr *aid_mgr)
+{
+	if (!aid_mgr)
+		return;
+
+	if (!qdf_atomic_dec_and_test(&aid_mgr->ref_cnt))
+		return;
+
+	aid_mgr->max_aid = 0;
+	qdf_mem_free(aid_mgr);
+}
+
+QDF_STATUS wlan_mlo_vdev_alloc_aid_mgr(struct wlan_mlo_dev_context *ml_dev,
+				       struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t i;
+	uint8_t is_mbss_enabled = 0;
+	struct wlan_objmgr_vdev *vdev_iter;
+	struct wlan_objmgr_vdev *tx_vdev = NULL;
+	struct wlan_vdev_aid_mgr *aid_mgr;
+	struct wlan_ml_vdev_aid_mgr *ml_aidmgr;
+	uint16_t max_aid = WLAN_UMAC_MAX_AID;
+
+	if (!ml_dev->ap_ctx) {
+		mlo_err(" ML AP context is not initialized");
+		QDF_BUG(0);
+		return QDF_STATUS_E_NOMEM;
+	}
+	ml_aidmgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aidmgr) {
+		mlo_err(" ML AID mgr allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev_iter = ml_dev->wlan_vdev_list[i];
+		if (!vdev_iter)
+			continue;
+
+		if (vdev != vdev_iter)
+			continue;
+
+		/* TODO */
+		/* Get Tx VDEV, if VDEV is MBSSID */
+		if (is_mbss_enabled) {
+			aid_mgr = wlan_vdev_mlme_get_aid_mgr(tx_vdev);
+			if (!aid_mgr) {
+				mlo_err("AID bitmap allocation failed for Tx VDEV%d",
+					wlan_vdev_get_id(tx_vdev));
+				return QDF_STATUS_E_NOMEM;
+			}
+			qdf_atomic_inc(&aid_mgr->ref_cnt);
+			ml_aidmgr->aid_mgr[i] = aid_mgr;
+			wlan_vdev_mlme_set_aid_mgr(vdev,
+						   ml_aidmgr->aid_mgr[i]);
+			break;
+		} else {
+			ml_aidmgr->aid_mgr[i] = wlan_vdev_aid_mgr_init(max_aid);
+			if (!ml_aidmgr->aid_mgr[i]) {
+				mlo_err("AID bitmap allocation failed for VDEV%d",
+					wlan_vdev_get_id(vdev));
+				return QDF_STATUS_E_NOMEM;
+			}
+			wlan_vdev_mlme_set_aid_mgr(vdev, ml_aidmgr->aid_mgr[i]);
+			break;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlo_vdev_free_aid_mgr(struct wlan_mlo_dev_context *ml_dev,
+				      struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t i;
+	struct wlan_objmgr_vdev *vdev_iter;
+	struct wlan_ml_vdev_aid_mgr *ml_aidmgr;
+
+	if (!ml_dev->ap_ctx) {
+		mlo_err(" ML AP context is not initialized");
+		QDF_BUG(0);
+		return QDF_STATUS_E_NOMEM;
+	}
+	ml_aidmgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aidmgr) {
+		mlo_err(" ML AID mgr allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev_iter = ml_dev->wlan_vdev_list[i];
+		if (!vdev_iter)
+			continue;
+
+		if (vdev != vdev_iter)
+			continue;
+
+		wlan_vdev_aid_mgr_free(ml_aidmgr->aid_mgr[i]);
+		ml_aidmgr->aid_mgr[i] = NULL;
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlo_vdev_aid_mgr_init(struct wlan_mlo_dev_context *ml_dev)
+{
+	uint8_t i;
+	uint8_t is_mbss_enabled = 0;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_vdev *tx_vdev = NULL;
+	struct wlan_vdev_aid_mgr *aid_mgr;
+	struct wlan_ml_vdev_aid_mgr *ml_aidmgr;
+	uint16_t max_aid = WLAN_UMAC_MAX_AID;
+
+	ml_aidmgr = qdf_mem_malloc(sizeof(struct wlan_ml_vdev_aid_mgr));
+	if (!ml_aidmgr) {
+		ml_dev->ap_ctx->ml_aid_mgr = NULL;
+		mlo_err(" ML AID mgr allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	ml_aidmgr->max_aid = max_aid;
+	ml_dev->ap_ctx->ml_aid_mgr = ml_aidmgr;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev = ml_dev->wlan_vdev_list[i];
+		if (!vdev)
+			continue;
+		/* TODO */
+		/* Get Tx VDEV, if VDEV is MBSSID */
+		if (is_mbss_enabled) {
+			aid_mgr = wlan_vdev_mlme_get_aid_mgr(tx_vdev);
+			if (!aid_mgr) {
+				mlo_err("AID bitmap allocation failed for Tx VDEV%d",
+					wlan_vdev_get_id(tx_vdev));
+				goto free_ml_aid_mgr;
+			}
+
+			qdf_atomic_inc(&aid_mgr->ref_cnt);
+			ml_aidmgr->aid_mgr[i] = aid_mgr;
+		} else {
+			ml_aidmgr->aid_mgr[i] = wlan_vdev_aid_mgr_init(max_aid);
+			if (!ml_aidmgr->aid_mgr[i]) {
+				mlo_err("AID bitmap allocation failed for VDEV%d",
+					wlan_vdev_get_id(vdev));
+				goto free_ml_aid_mgr;
+			}
+			wlan_vdev_mlme_set_aid_mgr(vdev,
+						   ml_aidmgr->aid_mgr[i]);
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+
+free_ml_aid_mgr:
+	wlan_mlo_vdev_aid_mgr_deinit(ml_dev);
+
+	return QDF_STATUS_E_NOMEM;
+}
+
+void wlan_mlo_vdev_aid_mgr_deinit(struct wlan_mlo_dev_context *ml_dev)
+{
+	uint8_t i;
+	struct wlan_ml_vdev_aid_mgr *ml_aid_mgr;
+	int32_t n;
+
+	ml_aid_mgr = ml_dev->ap_ctx->ml_aid_mgr;
+	if (!ml_aid_mgr)
+		return;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (!ml_dev->wlan_vdev_list[i])
+			continue;
+
+		if (ml_aid_mgr->aid_mgr[i]) {
+			n = qdf_atomic_read(&ml_aid_mgr->aid_mgr[i]->ref_cnt);
+			mlo_info("Vdev ID %d, AID mgr ref cnt %d",
+				 wlan_vdev_get_id(ml_dev->wlan_vdev_list[i]),
+				 n);
+		} else {
+			mlo_err("Vdev ID %d, doesn't have associated AID mgr",
+				wlan_vdev_get_id(ml_dev->wlan_vdev_list[i]));
+			continue;
+		}
+		wlan_vdev_aid_mgr_free(ml_aid_mgr->aid_mgr[i]);
+		ml_aid_mgr->aid_mgr[i] = NULL;
+	}
+
+	qdf_mem_free(ml_aid_mgr);
+	ml_dev->ap_ctx->ml_aid_mgr = NULL;
+}

+ 35 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_ap.c

@@ -204,3 +204,38 @@ void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev)
 {
 	mlo_ap_vdev_detach(vdev);
 }
+
+uint16_t mlo_ap_ml_peerid_alloc(void)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+	uint16_t i;
+
+	ml_peerid_lock_acquire(mlo_ctx);
+	for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) {
+		if (qdf_test_bit(i, mlo_ctx->mlo_peer_id_bmap))
+			continue;
+
+		qdf_set_bit(i, mlo_ctx->mlo_peer_id_bmap);
+		break;
+	}
+	ml_peerid_lock_release(mlo_ctx);
+
+	if (i == mlo_ctx->max_mlo_peer_id)
+		return MLO_INVALID_PEER_ID;
+
+	return i + 1;
+}
+
+void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (mlo_peer_id == MLO_INVALID_PEER_ID)
+		return;
+
+	ml_peerid_lock_acquire(mlo_ctx);
+	if (qdf_test_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap))
+		qdf_clear_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap);
+
+	ml_peerid_lock_release(mlo_ctx);
+}

+ 35 - 4
umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c

@@ -53,9 +53,12 @@ struct wlan_objmgr_vdev *mlo_get_vdev_by_link_id(
 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i]) &&
 		    dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id ==
 		    link_id) {
-			wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i],
-						     WLAN_MLO_MGR_ID);
-			partner_vdev = dev_ctx->wlan_vdev_list[i];
+			if (wlan_objmgr_vdev_try_get_ref(
+						dev_ctx->wlan_vdev_list[i],
+						WLAN_MLO_MGR_ID) ==
+							QDF_STATUS_SUCCESS)
+				partner_vdev = dev_ctx->wlan_vdev_list[i];
+
 			break;
 		}
 	}
@@ -132,7 +135,7 @@ QDF_STATUS mlo_mlme_create_link_vdev(struct wlan_objmgr_vdev *vdev,
 
 void mlo_mlme_peer_create(struct wlan_objmgr_vdev *vdev,
 			  struct wlan_mlo_peer_context *ml_peer,
-			  struct qdf_mac_addr addr,
+			  struct qdf_mac_addr *addr,
 			  qdf_nbuf_t frm_buf)
 {
 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
@@ -177,3 +180,31 @@ void mlo_mlme_peer_delete(struct wlan_objmgr_peer *peer)
 
 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete(peer);
 }
+
+void mlo_mlme_peer_assoc_resp(struct wlan_objmgr_peer *peer)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
+	    !mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp)
+		return;
+
+	mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp(peer);
+}
+
+uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *ml_dev,
+			     struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t i;
+
+	mlo_dev_lock_acquire(ml_dev);
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (vdev == ml_dev->wlan_vdev_list[i]) {
+			mlo_dev_lock_release(ml_dev);
+			return i;
+		}
+	}
+	mlo_dev_lock_release(ml_dev);
+
+	return (uint8_t)-1;
+}

+ 56 - 6
umac/mlo_mgr/src/wlan_mlo_mgr_main.c

@@ -17,12 +17,13 @@
 /*
  * 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_cmn.h>
 #include <wlan_objmgr_global_obj.h>
 #include "wlan_mlo_mgr_cmn.h"
+#include "wlan_mlo_mgr_main.h"
+#include <wlan_mlo_mgr_ap.h>
+#include <wlan_mlo_mgr_peer.h>
 
 static void mlo_global_ctx_deinit(void)
 {
@@ -34,7 +35,9 @@ static void mlo_global_ctx_deinit(void)
 	if (qdf_list_empty(&mlo_mgr_ctx->ml_dev_list))
 		mlo_err("ML dev list is not empty");
 
+	ml_peerid_lock_destroy(mlo_mgr_ctx);
 	ml_link_lock_destroy(mlo_mgr_ctx);
+	ml_aid_lock_destroy(mlo_mgr_ctx);
 	qdf_list_destroy(&mlo_mgr_ctx->ml_dev_list);
 
 	qdf_mem_free(mlo_mgr_ctx);
@@ -60,7 +63,10 @@ static void mlo_global_ctx_init(void)
 	wlan_objmgr_set_mlo_ctx(mlo_mgr_ctx);
 
 	qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV);
+	mlo_mgr_ctx->max_mlo_peer_id = MAX_MLO_PEER_ID;
+	ml_peerid_lock_create(mlo_mgr_ctx);
 	ml_link_lock_create(mlo_mgr_ctx);
+	ml_aid_lock_create(mlo_mgr_ctx);
 }
 
 QDF_STATUS wlan_mlo_mgr_init(void)
@@ -187,6 +193,34 @@ static inline struct wlan_mlo_dev_context
 	return NULL;
 }
 
+static QDF_STATUS mlo_ap_ctx_deinit(struct wlan_mlo_dev_context *ml_dev)
+{
+	wlan_mlo_vdev_aid_mgr_deinit(ml_dev);
+	qdf_mem_free(ml_dev->ap_ctx);
+	ml_dev->ap_ctx = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS mlo_ap_ctx_init(struct wlan_mlo_dev_context *ml_dev)
+{
+	struct wlan_mlo_ap *ap_ctx;
+
+	ap_ctx = qdf_mem_malloc(sizeof(*ap_ctx));
+	if (!ap_ctx) {
+		mlo_err("MLO AP ctx alloc failure");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	ml_dev->ap_ctx = ap_ctx;
+	if (wlan_mlo_vdev_aid_mgr_init(ml_dev) != QDF_STATUS_SUCCESS) {
+		mlo_ap_ctx_deinit(ml_dev);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 {
 	struct wlan_mlo_dev_context *ml_dev;
@@ -207,6 +241,10 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 			ml_dev->wlan_vdev_list[id] = vdev;
 			ml_dev->wlan_vdev_count++;
 			vdev->mlo_dev_ctx = ml_dev;
+
+			if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
+				wlan_mlo_vdev_alloc_aid_mgr(ml_dev, vdev);
+
 			break;
 		}
 		mlo_dev_lock_release(ml_dev);
@@ -224,6 +262,7 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 	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));
@@ -233,15 +272,16 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 			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) {
-			mlo_err("Failed to allocate memory for ap ctx");
+		if (mlo_ap_ctx_init(ml_dev) != QDF_STATUS_SUCCESS) {
 			mlo_dev_lock_destroy(ml_dev);
 			qdf_mem_free(ml_dev);
+			mlo_err("Failed to allocate memory for ap ctx");
 			return QDF_STATUS_E_NOMEM;
 		}
 	}
 
+	mlo_dev_mlpeer_list_init(ml_dev);
+
 	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);
@@ -268,6 +308,10 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
 		mlo_dev_lock_acquire(ml_dev);
 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
 			if (ml_dev->wlan_vdev_list[id] == vdev) {
+				if (wlan_vdev_mlme_get_opmode(vdev) ==
+								QDF_SAP_MODE)
+					wlan_mlo_vdev_free_aid_mgr(ml_dev,
+								   vdev);
 				ml_dev->wlan_vdev_list[id] = NULL;
 				ml_dev->wlan_vdev_count--;
 				vdev->mlo_dev_ctx = NULL;
@@ -277,8 +321,13 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
 		}
 		mlo_dev_lock_release(ml_dev);
 	}
+
 	ml_link_lock_acquire(g_mlo_ctx);
 	if (!ml_dev->wlan_vdev_count) {
+		if (ml_dev->ap_ctx)
+			mlo_ap_ctx_deinit(ml_dev);
+
+		mlo_dev_mlpeer_list_deinit(ml_dev);
 		qdf_list_remove_node(&g_mlo_ctx->ml_dev_list,
 				     &ml_dev->node);
 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
@@ -292,6 +341,7 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
 		}
 		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);
 	}

+ 216 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_msgq.c

@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+#include "wlan_mlo_mgr_main.h"
+#include "qdf_types.h"
+#include "wlan_cmn.h"
+#include "wlan_mlo_mgr_cmn.h"
+#include "wlan_mlo_mgr_msgq.h"
+#include "wlan_mlo_mgr_peer.h"
+
+#ifndef MLO_MSGQ_SUPPORT
+QDF_STATUS mlo_msgq_post(enum mlo_msg_type type,
+			 struct wlan_mlo_dev_context *ml_dev,
+			 void *payload)
+{
+	struct peer_create_notif_s *peer_create;
+	struct peer_assoc_notify_s *peer_assoc;
+	struct peer_assoc_fail_notify_s *peer_assoc_fail;
+	struct peer_discon_notify_s *peer_disconn;
+
+	switch (type) {
+	case MLO_PEER_CREATE:
+		peer_create = (struct peer_create_notif_s *)payload;
+
+		mlo_mlme_peer_create(peer_create->vdev_link,
+				     peer_create->ml_peer,
+				     &peer_create->addr, peer_create->frm_buf);
+		qdf_nbuf_free(peer_create->frm_buf);
+		wlan_mlo_peer_release_ref(peer_create->ml_peer);
+		wlan_objmgr_vdev_release_ref(peer_create->vdev_link,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_ASSOC:
+		peer_assoc = (struct peer_assoc_notify_s *)payload;
+		mlo_mlme_peer_assoc(peer_assoc->peer);
+		wlan_objmgr_peer_release_ref(peer_assoc->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_ASSOC_FAIL:
+		peer_assoc_fail = (struct peer_assoc_fail_notify_s *)payload;
+		mlo_mlme_peer_assoc_fail(peer_assoc_fail->peer);
+		wlan_objmgr_peer_release_ref(peer_assoc_fail->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_DISCONNECT:
+		peer_disconn = (struct peer_discon_notify_s *)payload;
+		mlo_mlme_peer_delete(peer_disconn->peer);
+		wlan_objmgr_peer_release_ref(peer_disconn->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	default:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+QDF_STATUS mlo_msgq_post(enum mlo_msg_type type,
+			 struct wlan_mlo_dev_context *ml_dev,
+			 void *payload)
+{
+	struct mlo_ctxt_switch_msg_s *msg;
+	struct peer_create_notif_s *peer_create, *peer_create_l;
+	struct peer_assoc_notify_s *peer_assoc, *peer_assoc_l;
+	struct peer_assoc_fail_notify_s *peer_assoc_fail, *peer_assoc_fail_l;
+	struct peer_discon_notify_s *peer_disconn, *peer_disconn_l;
+
+	msg = qdf_mem_malloc(sizeof(*msg));
+	if (!msg)
+		return QDF_STATUS_E_NOMEM;
+
+	msg->type = type;
+	msg->ml_dev = ml_dev;
+
+	switch (type) {
+	case MLO_PEER_CREATE:
+		peer_create = &msg->m.peer_create;
+		peer_create_l = (struct peer_create_notif_s *)payload;
+		peer_create->frm_buf = peer_create_l->frm_buf;
+		peer_create->ml_peer = peer_create_l->ml_peer;
+		peer_create->vdev_link = peer_create_l->vdev_link;
+		qdf_copy_macaddr(&peer_create->addr, &peer_create_l->addr);
+		break;
+
+	case MLO_PEER_ASSOC:
+		peer_assoc = &msg->m.peer_assoc;
+		peer_assoc_l = (struct peer_assoc_notify_s *)payload;
+		peer_assoc->peer = peer_assoc_l->peer;
+		break;
+
+	case MLO_PEER_ASSOC_FAIL:
+		peer_assoc_fail = &msg->m.peer_assoc_fail;
+		peer_assoc_fail_l = (struct peer_assoc_fail_notify_s *)payload;
+		peer_assoc_fail->peer = peer_assoc_fail_l->peer;
+		break;
+
+	case MLO_PEER_DISCONNECT:
+		peer_disconn = &msg->m.peer_disconn;
+		peer_disconn_l = (struct peer_discon_notify_s *)payload;
+		peer_disconn->peer = peer_disconn_l->peer;
+		break;
+
+	default:
+		break;
+	}
+	/* TODO queue message buffer to qdf_list */
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void mlo_msgq_msg_process_hdlr(struct mlo_ctxt_switch_msg_s *msg)
+{
+	enum mlo_msg_type type;
+	struct peer_create_notif_s *peer_create;
+	struct peer_assoc_notify_s *peer_assoc;
+	struct peer_assoc_fail_notify_s *peer_assoc_fail;
+	struct peer_discon_notify_s *peer_disconn;
+
+	type = msg->type;
+	switch (type) {
+	case MLO_PEER_CREATE:
+		peer_create = &msg->m.peer_create;
+		mlo_mlme_peer_create(peer_create->vdev_link,
+				     peer_create->ml_peer,
+				     &peer_create->addr, peer_create->frm_buf);
+		qdf_nbuf_free(peer_create->frm_buf);
+		wlan_mlo_peer_release_ref(peer_create->ml_peer);
+		wlan_objmgr_vdev_release_ref(peer_create->vdev_link,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_ASSOC:
+		peer_assoc = &msg->m.peer_assoc;
+		mlo_mlme_peer_assoc(peer_assoc->peer);
+		wlan_objmgr_peer_release_ref(peer_assoc->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_ASSOC_FAIL:
+		peer_assoc_fail = &msg->m.peer_assoc_fail;
+		mlo_mlme_peer_assoc_fail(peer_assoc_fail->peer);
+		wlan_objmgr_peer_release_ref(peer_assoc_fail->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_DISCONNECT:
+		peer_disconn = &msg->m.peer_disconn;
+		mlo_mlme_peer_delete(peer_disconn->peer);
+		wlan_objmgr_peer_release_ref(peer_disconn->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	default:
+		break;
+	}
+	qdf_mem_free(msg);
+}
+
+void mlo_msgq_msg_flush_hdlr(struct mlo_ctxt_switch_msg_s *msg)
+{
+	enum mlo_msg_type type;
+	struct peer_create_notif_s *peer_create;
+	struct peer_assoc_notify_s *peer_assoc;
+	struct peer_assoc_fail_notify_s *peer_assoc_fail;
+	struct peer_discon_notify_s *peer_disconn;
+
+	type = msg->type;
+	switch (type) {
+	case MLO_PEER_CREATE:
+		peer_create = &msg->m.peer_create;
+		qdf_nbuf_free(peer_create->frm_buf);
+		wlan_mlo_peer_release_ref(peer_create->ml_peer);
+		wlan_objmgr_vdev_release_ref(peer_create->vdev_link,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_ASSOC:
+		peer_assoc = &msg->m.peer_assoc;
+		wlan_objmgr_peer_release_ref(peer_assoc->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_ASSOC_FAIL:
+		peer_assoc_fail = &msg->m.peer_assoc_fail;
+		wlan_objmgr_peer_release_ref(peer_assoc_fail->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	case MLO_PEER_DISCONNECT:
+		peer_disconn = &msg->m.peer_disconn;
+		wlan_objmgr_peer_release_ref(peer_disconn->peer,
+					     WLAN_MLO_MGR_ID);
+		break;
+
+	default:
+		break;
+	}
+	qdf_mem_free(msg);
+}
+#endif

+ 606 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_peer.c

@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "wlan_mlo_mgr_main.h"
+#include "qdf_types.h"
+#include "wlan_cmn.h"
+#include "wlan_mlo_mgr_msgq.h"
+#include "wlan_mlo_mgr_peer.h"
+#include "wlan_mlo_mgr_ap.h"
+
+static void mlo_partner_peer_create_post(struct wlan_mlo_dev_context *ml_dev,
+					 struct wlan_objmgr_vdev *vdev_link,
+					 struct wlan_mlo_peer_context *ml_peer,
+					 qdf_nbuf_t frm_buf,
+					 struct mlo_partner_info *ml_info)
+{
+	struct peer_create_notif_s peer_create;
+	QDF_STATUS status;
+	uint8_t i;
+	uint8_t link_id;
+
+	if (wlan_objmgr_vdev_try_get_ref(vdev_link, WLAN_MLO_MGR_ID) ==
+							QDF_STATUS_SUCCESS) {
+		peer_create.vdev_link = vdev_link;
+	} else {
+		mlo_err("VDEV is not in created state");
+		return;
+	}
+
+	wlan_mlo_peer_get_ref(ml_peer);
+	peer_create.ml_peer = ml_peer;
+	link_id = wlan_vdev_get_link_id(vdev_link);
+	for (i = 0; i < ml_info->num_partner_links; i++) {
+		if (link_id != ml_info->partner_link_info[i].link_id)
+			continue;
+
+		qdf_copy_macaddr(&peer_create.addr,
+				 &ml_info->partner_link_info[i].link_addr);
+		break;
+	}
+
+	peer_create.frm_buf = qdf_nbuf_clone(frm_buf);
+	if (!peer_create.frm_buf) {
+		wlan_mlo_peer_release_ref(ml_peer);
+		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
+		mlo_err("nbuf clone is failed");
+		return;
+	}
+
+	status = mlo_msgq_post(MLO_PEER_CREATE, ml_dev, &peer_create);
+	if (status != QDF_STATUS_SUCCESS) {
+		qdf_nbuf_free(frm_buf);
+		wlan_mlo_peer_release_ref(ml_peer);
+		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
+	}
+}
+
+static void mlo_link_peer_assoc_notify(struct wlan_mlo_dev_context *ml_dev,
+				       struct wlan_objmgr_peer *peer)
+{
+	struct peer_assoc_notify_s peer_assoc;
+	QDF_STATUS status;
+
+	peer_assoc.peer = peer;
+	status = mlo_msgq_post(MLO_PEER_ASSOC, ml_dev, &peer_assoc);
+	if (status != QDF_STATUS_SUCCESS)
+		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
+}
+
+static void mlo_link_peer_send_assoc_fail(struct wlan_mlo_dev_context *ml_dev,
+					  struct wlan_objmgr_peer *peer)
+{
+	struct peer_assoc_fail_notify_s peer_assoc_fail;
+	QDF_STATUS status;
+
+	peer_assoc_fail.peer = peer;
+	status = mlo_msgq_post(MLO_PEER_ASSOC_FAIL, ml_dev, &peer_assoc_fail);
+	if (status != QDF_STATUS_SUCCESS)
+		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
+}
+
+static void mlo_link_peer_disconnect_notify(struct wlan_mlo_dev_context *ml_dev,
+					    struct wlan_objmgr_peer *peer)
+{
+	struct peer_discon_notify_s peer_disconn;
+	QDF_STATUS status;
+
+	peer_disconn.peer = peer;
+	status = mlo_msgq_post(MLO_PEER_DISCONNECT, ml_dev, &peer_disconn);
+	if (status != QDF_STATUS_SUCCESS)
+		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
+}
+
+QDF_STATUS
+wlan_mlo_peer_is_disconnect_progress(struct wlan_mlo_peer_context *ml_peer)
+{
+	QDF_STATUS status;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED)
+		status = QDF_STATUS_SUCCESS;
+	else
+		status = QDF_STATUS_E_FAILURE;
+
+	mlo_peer_lock_release(ml_peer);
+
+	return status;
+}
+
+QDF_STATUS wlan_mlo_peer_is_assoc_done(struct wlan_mlo_peer_context *ml_peer)
+{
+	QDF_STATUS status;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state == ML_PEER_ASSOC_DONE)
+		status = QDF_STATUS_SUCCESS;
+	else
+		status = QDF_STATUS_E_FAILURE;
+
+	mlo_peer_lock_release(ml_peer);
+
+	return status;
+}
+
+struct wlan_objmgr_peer *wlan_mlo_peer_get_assoc_peer(
+					struct wlan_mlo_peer_context *ml_peer)
+{
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	struct wlan_objmgr_peer *assoc_peer = NULL;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	peer_entry = &ml_peer->peer_list[0];
+
+	if (peer_entry->link_peer)
+		assoc_peer = peer_entry->link_peer;
+
+	mlo_peer_lock_release(ml_peer);
+
+	return assoc_peer;
+}
+
+void wlan_mlo_partner_peer_assoc_post(struct wlan_objmgr_peer *assoc_peer)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_mlo_peer_context *ml_peer;
+	struct wlan_objmgr_peer *link_peer;
+	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	uint16_t i;
+
+	ml_peer = assoc_peer->mlo_peer_ctx;
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state != ML_PEER_CREATED) {
+		mlo_peer_lock_release(ml_peer);
+		return;
+	}
+
+	ml_peer->mlpeer_state = ML_PEER_ASSOC_DONE;
+	ml_dev = ml_peer->ml_dev;
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		link_peers[i] = NULL;
+		peer_entry = &ml_peer->peer_list[i];
+
+		if (!peer_entry->link_peer)
+			continue;
+
+		if (peer_entry->link_peer == assoc_peer)
+			continue;
+
+		link_peer = peer_entry->link_peer;
+
+		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
+						QDF_STATUS_SUCCESS)
+			continue;
+
+		link_peers[i] = link_peer;
+	}
+	mlo_peer_lock_release(ml_peer);
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		if (!link_peers[i])
+			continue;
+
+		/* Prepare and queue message */
+		mlo_link_peer_assoc_notify(ml_dev, link_peers[i]);
+	}
+}
+
+void
+wlan_mlo_partner_peer_create_failed_notify(
+				struct wlan_mlo_peer_context *ml_peer)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_objmgr_peer *link_peer;
+	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	uint16_t i;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
+		mlo_peer_lock_release(ml_peer);
+		return;
+	}
+
+	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
+	ml_dev = ml_peer->ml_dev;
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		link_peers[i] = NULL;
+		peer_entry = &ml_peer->peer_list[i];
+		if (!peer_entry->link_peer)
+			continue;
+
+		link_peer = peer_entry->link_peer;
+		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
+						QDF_STATUS_SUCCESS)
+			continue;
+
+		link_peers[i] = link_peer;
+	}
+	mlo_peer_lock_release(ml_peer);
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		if (!link_peers[i])
+			continue;
+
+		/* Prepare and queue message */
+		if (i == 0)
+			mlo_link_peer_send_assoc_fail(ml_dev, link_peers[i]);
+		else
+			mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
+	}
+}
+
+void wlan_mlo_partner_peer_disconnect_notify(struct wlan_objmgr_peer *src_peer)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_mlo_peer_context *ml_peer;
+	struct wlan_objmgr_peer *link_peer;
+	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	uint16_t i;
+
+	ml_peer = src_peer->mlo_peer_ctx;
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
+		mlo_peer_lock_release(ml_peer);
+		return;
+	}
+
+	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
+	ml_dev = ml_peer->ml_dev;
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		link_peers[i] = NULL;
+		peer_entry = &ml_peer->peer_list[i];
+		if (!peer_entry->link_peer)
+			continue;
+
+		if (peer_entry->link_peer == src_peer)
+			continue;
+
+		link_peer = peer_entry->link_peer;
+		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
+						QDF_STATUS_SUCCESS)
+			continue;
+
+		link_peers[i] = link_peer;
+	}
+	mlo_peer_lock_release(ml_peer);
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		if (!link_peers[i])
+			continue;
+
+		/* Prepare and queue message */
+		mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
+	}
+}
+
+static void mlo_peer_populate_link_peer(
+			struct wlan_mlo_peer_context *ml_peer,
+			struct wlan_objmgr_peer *link_peer)
+{
+	mlo_peer_lock_acquire(ml_peer);
+	wlan_mlo_peer_get_ref(ml_peer);
+	link_peer->mlo_peer_ctx = ml_peer;
+	mlo_peer_lock_release(ml_peer);
+}
+
+static void mlo_reset_link_peer(
+			struct wlan_mlo_peer_context *ml_peer,
+			struct wlan_objmgr_peer *link_peer)
+{
+	mlo_peer_lock_acquire(ml_peer);
+	link_peer->mlo_peer_ctx = NULL;
+	mlo_peer_lock_release(ml_peer);
+}
+
+void mlo_peer_free(struct wlan_mlo_peer_context *ml_peer)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+
+	ml_dev = ml_peer->ml_dev;
+	if (!ml_dev) {
+		mlo_err("ML DEV is NULL");
+		return;
+	}
+
+	mlo_peer_lock_destroy(ml_peer);
+	mlo_ap_ml_peerid_free(ml_peer->mlo_peer_id);
+	mlo_peer_free_aid(ml_dev, ml_peer);
+	mlo_peer_free_primary_umac(ml_dev, ml_peer);
+	mlo_dev_mlpeer_detach(ml_dev, ml_peer);
+	qdf_mem_free(ml_peer);
+}
+
+static QDF_STATUS mlo_peer_attach_link_peer(
+		struct wlan_mlo_peer_context *ml_peer,
+		struct wlan_objmgr_peer *link_peer)
+{
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	QDF_STATUS status = QDF_STATUS_E_RESOURCES;
+	uint16_t i;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state != ML_PEER_CREATED) {
+		mlo_peer_lock_release(ml_peer);
+		return status;
+	}
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		peer_entry = &ml_peer->peer_list[i];
+		if (peer_entry->link_peer)
+			continue;
+
+		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
+						QDF_STATUS_SUCCESS)
+			break;
+
+		peer_entry->link_peer = link_peer;
+		qdf_copy_macaddr(&peer_entry->link_addr,
+				 (struct qdf_mac_addr *)&link_peer->macaddr[0]);
+
+		peer_entry->link_ix = i + 1;
+		peer_entry->hw_link_id = 1;
+			/*wlan_peer_get_hw_link_id(link_peer)TODO*/
+		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
+
+		status = QDF_STATUS_SUCCESS;
+		break;
+	}
+	if (QDF_IS_STATUS_SUCCESS(status))
+		ml_peer->link_peer_cnt++;
+
+	mlo_peer_lock_release(ml_peer);
+
+	return status;
+}
+
+static QDF_STATUS mlo_peer_detach_link_peer(
+		struct wlan_mlo_peer_context *ml_peer,
+		struct wlan_objmgr_peer *link_peer)
+{
+	struct wlan_mlo_link_peer_entry *peer_entry;
+	QDF_STATUS status = QDF_STATUS_E_RESOURCES;
+	uint16_t i;
+
+	mlo_peer_lock_acquire(ml_peer);
+
+	if (ml_peer->mlpeer_state != ML_PEER_DISCONN_INITIATED) {
+		mlo_peer_lock_release(ml_peer);
+		return status;
+	}
+
+	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
+		peer_entry = &ml_peer->peer_list[i];
+		if (!peer_entry->link_peer)
+			continue;
+
+		if (peer_entry->link_peer != link_peer)
+			continue;
+
+		wlan_objmgr_peer_release_ref(link_peer, WLAN_MLO_MGR_ID);
+		peer_entry->link_peer = NULL;
+		ml_peer->link_peer_cnt--;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	}
+	mlo_peer_lock_release(ml_peer);
+
+	return status;
+}
+
+static QDF_STATUS mlo_dev_get_link_vdevs(
+			struct wlan_objmgr_vdev *vdev,
+			struct wlan_mlo_dev_context *ml_dev,
+			struct mlo_partner_info *ml_info,
+			struct wlan_objmgr_vdev *link_vdevs[])
+{
+	uint16_t i, j;
+	struct wlan_objmgr_vdev *vdev_link;
+	uint8_t link_id;
+
+	for (i = 0; i < ml_info->num_partner_links; i++) {
+		link_id = ml_info->partner_link_info[i].link_id;
+		vdev_link = mlo_get_vdev_by_link_id(vdev, link_id);
+		if (vdev_link) {
+			link_vdevs[i] = vdev_link;
+		} else {
+			/* release ref which were taken before failure */
+			for (j = 0; j < i; j++) {
+				vdev_link = link_vdevs[j];
+				if (!vdev_link)
+					continue;
+
+				wlan_objmgr_vdev_release_ref(vdev_link,
+							     WLAN_MLO_MGR_ID);
+			}
+			mlo_dev_lock_release(ml_dev);
+			return QDF_STATUS_E_INVAL;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void mlo_dev_release_link_vdevs(
+			struct wlan_objmgr_vdev *link_vdevs[])
+{
+	uint16_t i;
+	struct wlan_objmgr_vdev *vdev_link;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev_link = link_vdevs[i];
+		if (!vdev_link)
+			continue;
+
+		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
+	}
+}
+
+QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev,
+				struct wlan_objmgr_peer *link_peer,
+				struct mlo_partner_info *ml_info,
+				qdf_nbuf_t frm_buf,
+				uint16_t aid)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct wlan_mlo_peer_context *ml_peer;
+	struct wlan_objmgr_vdev *link_vdevs[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL };
+	struct wlan_objmgr_vdev *vdev_link;
+	QDF_STATUS status;
+	uint16_t i;
+
+	/* get ML VDEV from VDEV */
+	ml_dev = vdev->mlo_dev_ctx;
+
+	/* Check resources of Partner VDEV */
+	status = mlo_dev_get_link_vdevs(vdev, ml_dev, ml_info, link_vdevs);
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_FAILURE;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev_link = link_vdevs[i];
+		if (!vdev_link)
+			continue;
+
+		if (wlan_vdev_is_peer_create_allowed(vdev_link)
+			!= QDF_STATUS_SUCCESS) {
+			mlo_dev_release_link_vdevs(link_vdevs);
+			return QDF_STATUS_E_INVAL;
+		}
+	}
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev_link = link_vdevs[i];
+		if (vdev_link && (vdev_link != vdev) &&
+		    (wlan_vdev_get_peer_count(vdev_link) >
+		     wlan_vdev_get_max_peer_count(vdev_link))) {
+			mlo_dev_release_link_vdevs(link_vdevs);
+			return QDF_STATUS_E_RESOURCES;
+		}
+	}
+
+	/* Allocate MLO peer */
+	ml_peer = qdf_mem_malloc(sizeof(*ml_peer));
+	if (!ml_peer) {
+		mlo_dev_release_link_vdevs(link_vdevs);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_atomic_init(&ml_peer->ref_cnt);
+	mlo_peer_lock_create(ml_peer);
+	ml_peer->ml_dev = ml_dev;
+	ml_peer->mlpeer_state = ML_PEER_CREATED;
+	ml_peer->max_links = ml_info->num_partner_links;
+	ml_peer->primary_umac_psoc_id = ML_PRIMARY_UMAC_ID_INVAL;
+	ml_peer->mlo_peer_id = mlo_ap_ml_peerid_alloc();
+	qdf_copy_macaddr((struct qdf_mac_addr *)&ml_peer->peer_mld_addr,
+			 (struct qdf_mac_addr *)&link_peer->mldaddr[0]);
+	/* Allocate AID */
+	if (aid == (uint16_t)-1)
+		mlo_peer_allocate_aid(ml_dev, ml_peer);
+	else
+		ml_peer->assoc_id = aid;
+
+	/* Populate Link peer pointer, peer MAC address,
+	 * MLD address. HW link ID, update ref count
+	 */
+	mlo_peer_attach_link_peer(ml_peer, link_peer);
+
+	/* Allocate Primary UMAC */
+	mlo_peer_allocate_primary_umac(ml_dev, ml_peer, link_vdevs);
+
+	/* Store AID, MLO Peer pointer in link peer, take link peer ref count */
+	mlo_peer_populate_link_peer(ml_peer, link_peer);
+
+	/* Attach MLO peer to ML Peer table */
+	status = mlo_dev_mlpeer_attach(ml_dev, ml_peer);
+	if (status != QDF_STATUS_SUCCESS) {
+		mlo_reset_link_peer(ml_peer, link_peer);
+		mlo_peer_free(ml_peer);
+		mlo_dev_release_link_vdevs(link_vdevs);
+		return status;
+	}
+
+	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
+		/* Notify other vdevs about link peer creation */
+		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+			vdev_link = link_vdevs[i];
+			if (!vdev_link)
+				continue;
+
+			if (vdev_link == vdev)
+				continue;
+
+			mlo_partner_peer_create_post(ml_dev, vdev_link,
+						     ml_peer, frm_buf, ml_info);
+		}
+	}
+	mlo_dev_release_link_vdevs(link_vdevs);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer,
+				     struct wlan_objmgr_peer *peer)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_peer *assoc_peer;
+
+	/* Populate Link peer pointer, peer MAC address,
+	 * MLD address. HW link ID, update ref count
+	 */
+	status = mlo_peer_attach_link_peer(ml_peer, peer);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	/* Store AID, MLO Peer pointer in link peer, take link peer ref count */
+	mlo_peer_populate_link_peer(ml_peer, peer);
+
+	if (ml_peer->max_links == ml_peer->link_peer_cnt) {
+		assoc_peer = ml_peer->peer_list[0].link_peer;
+		if (assoc_peer)
+			mlo_mlme_peer_assoc_resp(assoc_peer);
+	}
+
+	return status;
+}
+
+QDF_STATUS wlan_mlo_link_peer_delete(struct wlan_objmgr_peer *peer)
+{
+	struct wlan_mlo_peer_context *ml_peer;
+
+	ml_peer = peer->mlo_peer_ctx;
+
+	if (!ml_peer)
+		return QDF_STATUS_E_NOENT;
+
+	mlo_reset_link_peer(ml_peer, peer);
+	mlo_peer_detach_link_peer(ml_peer, peer);
+	wlan_mlo_peer_release_ref(ml_peer);
+
+	return QDF_STATUS_SUCCESS;
+}

+ 373 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_peer_list.c

@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <wlan_mlo_mgr_public_structs.h>
+#include "wlan_mlo_mgr_main.h"
+#include "qdf_types.h"
+#include "wlan_cmn.h"
+#include "wlan_mlo_mgr_peer.h"
+
+struct aid_search {
+	struct wlan_mlo_peer_context *ml_peer;
+	uint16_t aid;
+};
+
+struct mlpeerid_search {
+	struct wlan_mlo_peer_context *ml_peer;
+	uint16_t ml_peerid;
+};
+
+struct link_mac_search {
+	struct wlan_mlo_peer_context *ml_peer;
+	struct qdf_mac_addr mac_addr;
+};
+
+static inline struct wlan_mlo_peer_context *wlan_mlo_peer_list_peek_head(
+					qdf_list_t *peer_list)
+{
+	struct wlan_mlo_peer_context *ml_peer;
+	qdf_list_node_t *peer_node = NULL;
+
+	/* This API is invoked with lock acquired, do not add log prints */
+	if (qdf_list_peek_front(peer_list, &peer_node) != QDF_STATUS_SUCCESS)
+		return NULL;
+
+	ml_peer = qdf_container_of(peer_node,
+				   struct wlan_mlo_peer_context, peer_node);
+	return ml_peer;
+}
+
+static inline struct wlan_mlo_peer_context *wlan_mlo_peer_get_next_mlpeer(
+					qdf_list_t *peer_list,
+					struct wlan_mlo_peer_context *ml_peer)
+{
+	struct wlan_mlo_peer_context *next_peer;
+	qdf_list_node_t *node = &ml_peer->peer_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(peer_list, node, &next_node) !=
+				QDF_STATUS_SUCCESS)
+		return NULL;
+
+	next_peer = qdf_container_of(next_node,
+				     struct wlan_mlo_peer_context, peer_node);
+
+	return next_peer;
+}
+
+static inline struct wlan_mlo_peer_context *mlo_get_mlpeer(
+				struct wlan_mlo_dev_context *ml_dev,
+				struct qdf_mac_addr *ml_addr)
+{
+	uint8_t hash_index;
+	struct wlan_mlo_peer_list *mlo_peer_list;
+	struct wlan_mlo_peer_context *ml_peer;
+	struct wlan_mlo_peer_context *next_ml_peer;
+	qdf_list_t *peer_hash_list;
+
+	mlo_peer_list = &ml_dev->mlo_peer_list;
+	hash_index = WLAN_PEER_HASH(ml_addr->bytes);
+
+	peer_hash_list = &mlo_peer_list->peer_hash[hash_index];
+	/* Get first vdev */
+	ml_peer = wlan_mlo_peer_list_peek_head(peer_hash_list);
+	/**
+	 * Iterate through pdev's vdev list, till vdev id matches with
+	 * entry of vdev list
+	 */
+	while (ml_peer) {
+		if (qdf_is_macaddr_equal(&ml_peer->peer_mld_addr, ml_addr))
+			return ml_peer;
+
+		/* get next vdev */
+		next_ml_peer = wlan_mlo_peer_get_next_mlpeer(peer_hash_list,
+							     ml_peer);
+		ml_peer = next_ml_peer;
+	}
+
+	return NULL;
+}
+
+QDF_STATUS wlan_mlo_iterate_ml_peerlist(struct wlan_mlo_dev_context *ml_dev,
+					wlan_mlo_op_handler handler,
+					void *arg)
+{
+	uint8_t hash_index;
+	struct wlan_mlo_peer_list *peerlist;
+	struct wlan_mlo_peer_context *ml_peer;
+	struct wlan_mlo_peer_context *next;
+	qdf_list_t *peer_hash_list;
+	QDF_STATUS status;
+
+	peerlist = &ml_dev->mlo_peer_list;
+	ml_peerlist_lock_acquire(peerlist);
+
+	for (hash_index = 0; hash_index < WLAN_PEER_HASHSIZE; hash_index++) {
+		peer_hash_list = &peerlist->peer_hash[hash_index];
+		/* Get first vdev */
+		ml_peer = wlan_mlo_peer_list_peek_head(peer_hash_list);
+		/**
+		 * Iterate through pdev's vdev list, till vdev id matches with
+		 * entry of vdev list
+		 */
+		while (ml_peer) {
+			status = handler(ml_dev, ml_peer, arg);
+			if (status == QDF_STATUS_SUCCESS) {
+				ml_peerlist_lock_release(peerlist);
+				return QDF_STATUS_SUCCESS;
+			}
+			/* get next ml peer */
+			next = wlan_mlo_peer_get_next_mlpeer(peer_hash_list,
+							     ml_peer);
+			ml_peer = next;
+		}
+	}
+	ml_peerlist_lock_release(peerlist);
+
+	return QDF_STATUS_E_NOENT;
+}
+
+static QDF_STATUS
+wlan_find_mlpeer_link_mac_addr(struct wlan_mlo_dev_context *ml_dev,
+			       void *iter_ml_peer,
+			       void *arg)
+{
+	struct link_mac_search *link_mac_arg = (struct link_mac_search *)arg;
+	struct wlan_mlo_link_peer_entry *link_peer;
+	struct wlan_mlo_peer_context *ml_peer;
+	uint8_t i;
+
+	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
+	for (i = 0; i < MAX_MLO_PEER; i++) {
+		link_peer = &ml_peer->peer_list[i];
+		if (!link_peer)
+			continue;
+
+		if (qdf_is_macaddr_equal(&link_mac_arg->mac_addr,
+					 &link_peer->link_addr)) {
+			link_mac_arg->ml_peer = ml_peer;
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+	return QDF_STATUS_E_NOENT;
+}
+
+static QDF_STATUS wlan_find_mlpeer_aid(struct wlan_mlo_dev_context *ml_dev,
+				       void *iter_ml_peer,
+				       void *arg)
+{
+	struct aid_search *aid_arg = (struct aid_search *)arg;
+	struct wlan_mlo_peer_context *ml_peer;
+
+	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
+
+	if (aid_arg->aid == ml_peer->assoc_id) {
+		aid_arg->ml_peer = ml_peer;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_NOENT;
+}
+
+static QDF_STATUS
+wlan_find_mlpeer_ml_peerid(struct wlan_mlo_dev_context *ml_dev,
+			   void *iter_ml_peer,
+			   void *arg)
+{
+	struct mlpeerid_search *mlpeer_id_arg = (struct mlpeerid_search *)arg;
+	struct wlan_mlo_peer_context *ml_peer;
+
+	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
+
+	if (mlpeer_id_arg->ml_peerid == ml_peer->mlo_peer_id) {
+		mlpeer_id_arg->ml_peer = ml_peer;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_NOENT;
+}
+
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_linkmac(
+				struct wlan_mlo_dev_context *ml_dev,
+				struct qdf_mac_addr *link_mac)
+{
+	struct link_mac_search link_mac_arg;
+	QDF_STATUS status;
+
+	qdf_copy_macaddr(&link_mac_arg.mac_addr, link_mac);
+	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
+					      wlan_find_mlpeer_link_mac_addr,
+					      &link_mac_arg);
+	if (status == QDF_STATUS_SUCCESS)
+		return link_mac_arg.ml_peer;
+
+	/* TODO: Take ref */
+
+	return NULL;
+}
+
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_aid(
+				struct wlan_mlo_dev_context *ml_dev,
+				uint16_t assoc_id)
+{
+	struct aid_search aid_arg;
+	QDF_STATUS status;
+
+	aid_arg.aid = assoc_id;
+	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
+					      wlan_find_mlpeer_aid,
+					      &aid_arg);
+	if (status == QDF_STATUS_SUCCESS)
+		return aid_arg.ml_peer;
+
+	/* TODO: Take ref */
+
+	return NULL;
+}
+
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_ml_peerid(
+				struct wlan_mlo_dev_context *ml_dev,
+				uint16_t ml_peerid)
+{
+	struct mlpeerid_search peerid_arg;
+	QDF_STATUS status;
+
+	peerid_arg.ml_peerid = ml_peerid;
+	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
+					      wlan_find_mlpeer_ml_peerid,
+					      &peerid_arg);
+	if (status == QDF_STATUS_SUCCESS)
+		return peerid_arg.ml_peer;
+
+	/* TODO: Take ref */
+
+	return NULL;
+}
+
+struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer(
+				struct wlan_mlo_dev_context *ml_dev,
+				struct qdf_mac_addr *ml_addr)
+{
+	struct wlan_mlo_peer_context *ml_peer;
+	struct wlan_mlo_peer_list *mlo_peer_list;
+
+	mlo_peer_list = &ml_dev->mlo_peer_list;
+	ml_peerlist_lock_acquire(mlo_peer_list);
+	ml_peer = mlo_get_mlpeer(ml_dev, ml_addr);
+	if (!ml_peer) {
+		ml_peerlist_lock_release(mlo_peer_list);
+		return NULL;
+	}
+	/* TODO: Take ref */
+
+	ml_peerlist_lock_release(mlo_peer_list);
+	return ml_peer;
+}
+
+static void wlan_mlo_peerlist_add_tail(qdf_list_t *obj_list,
+				       struct wlan_mlo_peer_context *obj)
+{
+	qdf_list_insert_back(obj_list, &obj->peer_node);
+}
+
+static QDF_STATUS wlan_mlo_peerlist_remove_mlpeer(
+				qdf_list_t *obj_list,
+				struct wlan_mlo_peer_context *ml_peer)
+{
+	qdf_list_node_t *peer_node = NULL;
+
+	if (!ml_peer)
+		return QDF_STATUS_E_FAILURE;
+	/* get vdev list node element */
+	peer_node = &ml_peer->peer_node;
+	/* list is empty, return failure */
+	if (qdf_list_remove_node(obj_list, peer_node) != QDF_STATUS_SUCCESS)
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS mlo_dev_mlpeer_attach(struct wlan_mlo_dev_context *ml_dev,
+				 struct wlan_mlo_peer_context *ml_peer)
+{
+	uint8_t hash_index;
+	struct wlan_mlo_peer_list *mlo_peer_list;
+
+	mlo_peer_list = &ml_dev->mlo_peer_list;
+	ml_peerlist_lock_acquire(mlo_peer_list);
+	if (mlo_get_mlpeer(ml_dev, &ml_peer->peer_mld_addr)) {
+		ml_peerlist_lock_release(mlo_peer_list);
+		return QDF_STATUS_E_EXISTS;
+	}
+
+	hash_index = WLAN_PEER_HASH(ml_peer->peer_mld_addr.bytes);
+	wlan_mlo_peerlist_add_tail(&mlo_peer_list->peer_hash[hash_index],
+				   ml_peer);
+	ml_peerlist_lock_release(mlo_peer_list);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS mlo_dev_mlpeer_detach(struct wlan_mlo_dev_context *ml_dev,
+				 struct wlan_mlo_peer_context *ml_peer)
+{
+	uint8_t hash_index;
+	QDF_STATUS status;
+	struct wlan_mlo_peer_list *mlo_peer_list;
+
+	mlo_peer_list = &ml_dev->mlo_peer_list;
+	ml_peerlist_lock_acquire(mlo_peer_list);
+	hash_index = WLAN_PEER_HASH(ml_peer->peer_mld_addr.bytes);
+	status = wlan_mlo_peerlist_remove_mlpeer(
+					&mlo_peer_list->peer_hash[hash_index],
+					ml_peer);
+	ml_peerlist_lock_release(mlo_peer_list);
+
+	return status;
+}
+
+QDF_STATUS mlo_dev_mlpeer_list_init(struct wlan_mlo_dev_context *ml_dev)
+{
+	struct wlan_mlo_peer_list *mlo_peer_list;
+	uint16_t i;
+
+	mlo_peer_list = &ml_dev->mlo_peer_list;
+	ml_peerlist_lock_create(mlo_peer_list);
+	for (i = 0; i < WLAN_PEER_HASHSIZE; i++)
+		qdf_list_create(&mlo_peer_list->peer_hash[i],
+				WLAN_UMAC_PSOC_MAX_PEERS +
+				WLAN_MAX_PSOC_TEMP_PEERS);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS mlo_dev_mlpeer_list_deinit(struct wlan_mlo_dev_context *ml_dev)
+{
+	uint16_t i;
+	struct wlan_mlo_peer_list *mlo_peer_list;
+
+	/* deinit the lock */
+	mlo_peer_list = &ml_dev->mlo_peer_list;
+	ml_peerlist_lock_destroy(mlo_peer_list);
+	for (i = 0; i < WLAN_PEER_HASHSIZE; i++)
+		qdf_list_destroy(&mlo_peer_list->peer_hash[i]);
+
+	return QDF_STATUS_SUCCESS;
+}

+ 62 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "wlan_mlo_mgr_main.h"
+#include "qdf_types.h"
+#include "wlan_cmn.h"
+#include "wlan_mlo_mgr_peer.h"
+#include <wlan_mlo_mgr_ap.h>
+
+void mlo_peer_assign_primary_umac(
+		struct wlan_mlo_peer_context *ml_peer,
+		struct wlan_mlo_link_peer_entry *peer_entry)
+{
+	if (wlan_peer_get_psoc_id(peer_entry->link_peer) ==
+			ml_peer->primary_umac_psoc_id)
+		peer_entry->is_primary = true;
+	else
+		peer_entry->is_primary = false;
+}
+
+QDF_STATUS mlo_peer_allocate_primary_umac(
+		struct wlan_mlo_dev_context *ml_dev,
+		struct wlan_mlo_peer_context *ml_peer,
+		struct wlan_objmgr_vdev *link_vdevs[])
+{
+	struct wlan_objmgr_vdev *vdev;
+	uint16_t link_load[WLAN_UMAC_MLO_MAX_VDEVS];
+	uint8_t i;
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		vdev = ml_dev->wlan_vdev_list[i];
+		if (!vdev) {
+			link_load[i] = 0;
+			continue;
+		}
+
+		link_load[i] = 1/* TODO mlo_get_umac_load(vdev)*/;
+	}
+	ml_peer->primary_umac_psoc_id = 0;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS mlo_peer_free_primary_umac(
+		struct wlan_mlo_dev_context *ml_dev,
+		struct wlan_mlo_peer_context *ml_peer)
+{
+	return QDF_STATUS_SUCCESS;
+}