Browse Source

qcacmn: Add Support for MLO device Context Struct

Add support for below operations for MLO device
context structure.
1) Allocate MLO device structure
2) Attach vdev to MLO device structure
3) Detach vdev from MLO device structure
4) Free MLO device structure

Change-Id: Ifc282a5a04657aa618e0dac6a64d118aa8a8f422
CRs-Fixed: 3566880
Kenvish Butani 1 year ago
parent
commit
8e969e5393
5 changed files with 615 additions and 0 deletions
  1. 452 0
      dp/wifi3.0/be/dp_be.c
  2. 154 0
      dp/wifi3.0/be/dp_be.h
  3. 2 0
      dp/wifi3.0/be/mlo/dp_mlo.c
  4. 5 0
      dp/wifi3.0/be/mlo/dp_mlo.h
  5. 2 0
      dp/wifi3.0/dp_types.h

+ 452 - 0
dp/wifi3.0/be/dp_be.c

@@ -826,10 +826,12 @@ void dp_reo_shared_qaddr_detach(struct dp_soc *soc)
 static QDF_STATUS dp_soc_detach_be(struct dp_soc *soc)
 {
 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
+	dp_mlo_dev_obj_t mlo_dev_obj = dp_get_mlo_dev_list_obj(be_soc);
 	int i = 0;
 
 	dp_soc_ppeds_detach_be(soc);
 	dp_reo_shared_qaddr_detach(soc);
+	dp_mlo_dev_ctxt_list_detach_wrapper(mlo_dev_obj);
 
 	for (i = 0; i < MAX_TXDESC_POOLS; i++)
 		dp_hw_cookie_conversion_detach(be_soc,
@@ -964,6 +966,65 @@ static void dp_get_rx_hash_key_be(struct dp_soc *soc,
 {
 	dp_mlo_get_rx_hash_key(soc, lro_hash);
 }
+
+#ifdef WLAN_DP_MLO_DEV_CTX
+static inline void
+dp_attach_vdev_list_in_mlo_dev_ctxt(struct dp_soc_be *be_soc,
+				    struct dp_vdev *vdev,
+				    struct dp_mlo_dev_ctxt *mlo_dev_ctxt)
+{
+	uint8_t pdev_id = vdev->pdev->pdev_id;
+
+	qdf_spin_lock_bh(&mlo_dev_ctxt->vdev_list_lock);
+	if (vdev->is_bridge_vdev) {
+		if (mlo_dev_ctxt->bridge_vdev[be_soc->mlo_chip_id][pdev_id]
+		    != CDP_INVALID_VDEV_ID)
+			dp_alert("bridge vdevId in MLO dev ctx is not Invalid"
+				 "chip_id: %u, pdev_id: %u,"
+				 "existing vdev_id: %u, new vdev_id : %u",
+				 be_soc->mlo_chip_id, pdev_id,
+				 mlo_dev_ctxt->bridge_vdev[be_soc->mlo_chip_id][pdev_id],
+				 vdev->vdev_id);
+
+		mlo_dev_ctxt->bridge_vdev[be_soc->mlo_chip_id][pdev_id] =
+								vdev->vdev_id;
+		mlo_dev_ctxt->is_bridge_vdev_present = 1;
+	} else {
+		if (mlo_dev_ctxt->vdev_list[be_soc->mlo_chip_id][pdev_id]
+		    != CDP_INVALID_VDEV_ID)
+			dp_alert("vdevId in MLO dev ctx is not Invalid"
+				 "chip_id: %u, pdev_id: %u,"
+				 "existing vdev_id: %u, new vdev_id : %u",
+				 be_soc->mlo_chip_id, pdev_id,
+				 mlo_dev_ctxt->vdev_list[be_soc->mlo_chip_id][pdev_id],
+				 vdev->vdev_id);
+
+		mlo_dev_ctxt->vdev_list[be_soc->mlo_chip_id][pdev_id] =
+								vdev->vdev_id;
+	}
+	mlo_dev_ctxt->vdev_count++;
+	qdf_spin_unlock_bh(&mlo_dev_ctxt->vdev_list_lock);
+}
+
+static inline void
+dp_detach_vdev_list_in_mlo_dev_ctxt(struct dp_soc_be *be_soc,
+				    struct dp_vdev *vdev,
+				    struct dp_mlo_dev_ctxt *mlo_dev_ctxt)
+{
+	uint8_t pdev_id = vdev->pdev->pdev_id;
+
+	qdf_spin_lock_bh(&mlo_dev_ctxt->vdev_list_lock);
+	if (vdev->is_bridge_vdev) {
+		mlo_dev_ctxt->bridge_vdev[be_soc->mlo_chip_id][pdev_id] =
+							CDP_INVALID_VDEV_ID;
+	} else {
+		mlo_dev_ctxt->vdev_list[be_soc->mlo_chip_id][pdev_id] =
+							CDP_INVALID_VDEV_ID;
+	}
+	mlo_dev_ctxt->vdev_count--;
+	qdf_spin_unlock_bh(&mlo_dev_ctxt->vdev_list_lock);
+}
+#endif /* WLAN_DP_MLO_DEV_CTX */
 #else
 static inline void
 dp_mlo_mcast_init(struct dp_soc *soc, struct dp_vdev *vdev)
@@ -985,6 +1046,21 @@ static void dp_get_rx_hash_key_be(struct dp_soc *soc,
 	dp_get_rx_hash_key_bytes(lro_hash);
 }
 
+#ifdef WLAN_DP_MLO_DEV_CTX
+static inline void
+dp_attach_vdev_list_in_mlo_dev_ctxt(struct dp_soc_be *be_soc,
+				    struct dp_vdev *vdev,
+				    struct dp_mlo_dev_ctxt *mlo_dev_ctxt)
+{
+}
+
+static inline void
+dp_detach_vdev_list_in_mlo_dev_ctxt(struct dp_soc_be *be_soc,
+				    struct dp_vdev *vdev,
+				    struct dp_mlo_dev_ctxt *mlo_dev_ctxt)
+{
+}
+#endif /* WLAN_DP_MLO_DEV_CTX */
 #endif
 
 static QDF_STATUS dp_soc_attach_be(struct dp_soc *soc,
@@ -995,6 +1071,7 @@ static QDF_STATUS dp_soc_attach_be(struct dp_soc *soc,
 	uint32_t max_tx_rx_desc_num, num_spt_pages;
 	uint32_t num_entries;
 	int i = 0;
+	dp_mlo_dev_obj_t mlo_dev_obj = dp_get_mlo_dev_list_obj(be_soc);
 
 	max_tx_rx_desc_num = WLAN_CFG_NUM_TX_DESC_MAX * MAX_TXDESC_POOLS +
 		WLAN_CFG_RX_SW_DESC_NUM_SIZE_MAX * MAX_RXDESC_POOLS +
@@ -1019,6 +1096,12 @@ static QDF_STATUS dp_soc_attach_be(struct dp_soc *soc,
 
 	dp_soc_mlo_fill_params(soc, params);
 
+	/* Initialize common cdp mlo ops */
+	dp_soc_initialize_cdp_cmn_mlo_ops(soc);
+
+	/* Initialize MLO device ctxt list */
+	dp_mlo_dev_ctxt_list_attach_wrapper(mlo_dev_obj);
+
 	qdf_status = dp_soc_ppeds_attach_be(soc);
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 		goto fail;
@@ -2149,6 +2232,14 @@ static QDF_STATUS dp_mlo_peer_find_hash_attach_wrapper(struct dp_soc *soc)
 static void dp_mlo_peer_find_hash_detach_wrapper(struct dp_soc *soc)
 {
 }
+
+void dp_mlo_dev_ctxt_list_attach_wrapper(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+}
+
+void dp_mlo_dev_ctxt_list_detach_wrapper(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+}
 #else
 static QDF_STATUS dp_mlo_peer_find_hash_attach_wrapper(struct dp_soc *soc)
 {
@@ -2173,6 +2264,16 @@ static void dp_mlo_peer_find_hash_detach_wrapper(struct dp_soc *soc)
 
 	return dp_mlo_peer_find_hash_detach_be(mld_hash_obj);
 }
+
+void dp_mlo_dev_ctxt_list_attach_wrapper(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+	dp_mlo_dev_ctxt_list_attach(mlo_dev_obj);
+}
+
+void dp_mlo_dev_ctxt_list_detach_wrapper(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+	dp_mlo_dev_ctxt_list_detach(mlo_dev_obj);
+}
 #endif
 
 #ifdef QCA_ENHANCED_STATS_SUPPORT
@@ -2665,6 +2766,345 @@ static QDF_STATUS dp_peer_map_attach_be(struct dp_soc *soc)
 	return QDF_STATUS_SUCCESS;
 }
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_DP_MLO_DEV_CTX)
+
+void dp_mlo_dev_ctxt_list_attach(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+	TAILQ_INIT(&mlo_dev_obj->mlo_dev_list);
+	qdf_spinlock_create(&mlo_dev_obj->mlo_dev_list_lock);
+}
+
+void dp_mlo_dev_ctxt_list_detach(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+	struct dp_mlo_dev_ctxt *mld_ctxt = NULL;
+	struct dp_mlo_dev_ctxt *tmp_mld_ctxt = NULL;
+
+	if (!TAILQ_EMPTY(&mlo_dev_obj->mlo_dev_list)) {
+		dp_alert("DP MLO dev list is not empty");
+		qdf_spin_lock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+		TAILQ_FOREACH_SAFE(mld_ctxt, &mlo_dev_obj->mlo_dev_list,
+				   ml_dev_list_elem, tmp_mld_ctxt) {
+			if (mld_ctxt) {
+				dp_alert("MLD MAC " QDF_MAC_ADDR_FMT " ",
+					 QDF_MAC_ADDR_REF(
+						&mld_ctxt->mld_mac_addr.raw));
+				qdf_mem_free(mld_ctxt);
+			}
+		}
+		qdf_spin_unlock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+	}
+
+	qdf_spinlock_destroy(&mlo_dev_obj->mlo_dev_list_lock);
+}
+
+void dp_mlo_dev_ctxt_unref_delete(struct dp_mlo_dev_ctxt *mlo_dev_ctxt,
+				  enum dp_mod_id mod_id)
+{
+	QDF_ASSERT(qdf_atomic_dec_return(&mlo_dev_ctxt->mod_refs[mod_id]) >= 0);
+
+	/* Return if this is not the last reference*/
+	if (!qdf_atomic_dec_and_test(&mlo_dev_ctxt->ref_cnt))
+		return;
+
+	QDF_ASSERT(mlo_dev_ctxt->ref_delete_pending);
+	qdf_spinlock_destroy(&mlo_dev_ctxt->vdev_list_lock);
+	qdf_mem_free(mlo_dev_ctxt);
+}
+
+QDF_STATUS dp_mlo_dev_get_ref(struct dp_mlo_dev_ctxt *mlo_dev_ctxt,
+			      enum dp_mod_id mod_id)
+{
+	if (!qdf_atomic_inc_return(&mlo_dev_ctxt->ref_cnt))
+		return QDF_STATUS_E_INVAL;
+
+	qdf_atomic_inc(&mlo_dev_ctxt->mod_refs[mod_id]);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+struct dp_mlo_dev_ctxt *
+dp_get_mlo_dev_ctx_by_mld_mac_addr(struct dp_soc_be *be_soc,
+				   uint8_t *mldaddr,
+				   enum dp_mod_id mod_id)
+{
+	struct dp_mlo_dev_ctxt *mld_cur = NULL;
+	struct dp_mlo_dev_ctxt *tmp_mld_cur = NULL;
+	dp_mlo_dev_obj_t mlo_dev_obj = dp_get_mlo_dev_list_obj(be_soc);
+
+	if (!mlo_dev_obj) {
+		dp_err("DP Global MLO Context is NULL");
+		return NULL;
+	}
+
+	/*
+	 * Iterate through ml dev list, till mldaddr matches with
+	 * entry of list
+	 */
+	qdf_spin_lock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+	TAILQ_FOREACH_SAFE(mld_cur, &mlo_dev_obj->mlo_dev_list,
+			   ml_dev_list_elem, tmp_mld_cur) {
+		if (!qdf_mem_cmp(&mld_cur->mld_mac_addr.raw, mldaddr,
+				 QDF_MAC_ADDR_SIZE)) {
+			if (dp_mlo_dev_get_ref(mld_cur, mod_id)
+			    == QDF_STATUS_SUCCESS) {
+				qdf_spin_unlock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+				return mld_cur;
+			}
+		}
+	}
+	qdf_spin_unlock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+	return NULL;
+}
+
+/**
+ * dp_mlo_dev_ctxt_create() - Allocate DP MLO dev context
+ * @soc_hdl: SOC handle
+ * @mld_mac_addr: MLD MAC address
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_create(struct cdp_soc_t *soc_hdl,
+				  uint8_t *mld_mac_addr)
+{
+	struct dp_mlo_dev_ctxt *mlo_dev_ctxt = NULL;
+	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
+	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
+	dp_mlo_dev_obj_t mlo_dev_obj = dp_get_mlo_dev_list_obj(be_soc);
+
+	if (!mlo_dev_obj) {
+		dp_err("DP Global MLO Context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* check if MLO dev ctx already available */
+	mlo_dev_ctxt = dp_get_mlo_dev_ctx_by_mld_mac_addr(be_soc,
+							  mld_mac_addr,
+							  DP_MOD_ID_MLO_DEV);
+	if (mlo_dev_ctxt) {
+		dp_mlo_dev_ctxt_unref_delete(mlo_dev_ctxt, DP_MOD_ID_MLO_DEV);
+		/* assert if we get two create request for same MLD MAC */
+		qdf_assert_always(0);
+	}
+
+	/* Allocate MLO dev ctx */
+	mlo_dev_ctxt = qdf_mem_malloc(sizeof(struct dp_mlo_dev_ctxt));
+
+	if (!mlo_dev_ctxt) {
+		dp_err("Failed to allocate DP MLO Dev Context");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_copy_macaddr((struct qdf_mac_addr *)&mlo_dev_ctxt->mld_mac_addr.raw[0],
+			 (struct qdf_mac_addr *)mld_mac_addr);
+
+	qdf_mem_set(mlo_dev_ctxt->vdev_list,
+		    WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC,
+		    CDP_INVALID_VDEV_ID);
+	qdf_mem_set(mlo_dev_ctxt->bridge_vdev,
+		    WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC,
+		    CDP_INVALID_VDEV_ID);
+
+	/* Add mlo_dev_ctxt to the global DP MLO list */
+	qdf_spin_lock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+	TAILQ_INSERT_TAIL(&mlo_dev_obj->mlo_dev_list,
+			  mlo_dev_ctxt, ml_dev_list_elem);
+	qdf_spin_unlock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+
+	/* Ref for MLO ctxt saved in global list */
+	dp_mlo_dev_get_ref(mlo_dev_ctxt, DP_MOD_ID_CONFIG);
+
+	mlo_dev_ctxt->ref_delete_pending = 0;
+	qdf_spinlock_create(&mlo_dev_ctxt->vdev_list_lock);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * dp_mlo_dev_ctxt_destroy() - Destroy DP MLO dev context
+ * @soc_hdl: SOC handle
+ * @mld_mac_addr: MLD MAC address
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_destroy(struct cdp_soc_t *soc_hdl,
+				   uint8_t *mld_mac_addr)
+{
+	struct dp_mlo_dev_ctxt *mlo_dev_ctxt = NULL;
+	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
+	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
+	dp_mlo_dev_obj_t mlo_dev_obj = dp_get_mlo_dev_list_obj(be_soc);
+
+	if (!mlo_dev_obj) {
+		dp_err("DP Global MLO Context is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* GET mlo_dev_ctxt from the global list */
+	mlo_dev_ctxt = dp_get_mlo_dev_ctx_by_mld_mac_addr(be_soc,
+							  mld_mac_addr,
+							  DP_MOD_ID_MLO_DEV);
+	if (!mlo_dev_ctxt) {
+		dp_err("Failed to get DP MLO Dev Context by MLD mac addr");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (mlo_dev_ctxt->vdev_count)
+		dp_alert("deleting MLO dev ctxt with non zero vdev count");
+
+	qdf_spin_lock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+	TAILQ_REMOVE(&mlo_dev_obj->mlo_dev_list,
+		     mlo_dev_ctxt, ml_dev_list_elem);
+	qdf_spin_unlock_bh(&mlo_dev_obj->mlo_dev_list_lock);
+
+	/* unref for MLO ctxt ref released from Global list */
+	dp_mlo_dev_ctxt_unref_delete(mlo_dev_ctxt, DP_MOD_ID_CONFIG);
+
+	mlo_dev_ctxt->ref_delete_pending = 1;
+	dp_mlo_dev_ctxt_unref_delete(mlo_dev_ctxt, DP_MOD_ID_MLO_DEV);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * dp_mlo_dev_ctxt_vdev_attach() - Attach vdev to DP MLO dev context
+ * @soc_hdl: SOC handle
+ * @vdev_id: vdev id for the vdev to be attached
+ * @mld_mac_addr: MLD MAC address
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_vdev_attach(struct cdp_soc_t *soc_hdl,
+				       uint8_t vdev_id,
+				       uint8_t *mld_mac_addr)
+{
+	struct dp_mlo_dev_ctxt *mlo_dev_ctxt = NULL;
+	struct dp_vdev *vdev = NULL;
+	struct dp_vdev_be *be_vdev = NULL;
+	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
+	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
+
+	vdev = dp_vdev_get_ref_by_id(soc, vdev_id, DP_MOD_ID_CDP);
+	if (!vdev)
+		return QDF_STATUS_E_FAILURE;
+	be_vdev = dp_get_be_vdev_from_dp_vdev(vdev);
+
+	/* GET mlo_dev_ctxt from the global list */
+	mlo_dev_ctxt = dp_get_mlo_dev_ctx_by_mld_mac_addr(be_soc,
+							  mld_mac_addr,
+							  DP_MOD_ID_MLO_DEV);
+	if (!mlo_dev_ctxt) {
+		dp_err("Failed to get MLO ctxt for " QDF_MAC_ADDR_FMT "",
+		       QDF_MAC_ADDR_REF(mld_mac_addr));
+		dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	dp_attach_vdev_list_in_mlo_dev_ctxt(be_soc, vdev, mlo_dev_ctxt);
+	be_vdev->mlo_dev_ctxt = mlo_dev_ctxt;
+
+	/* ref for holding MLO ctxt in be_vdev */
+	dp_mlo_dev_get_ref(mlo_dev_ctxt, DP_MOD_ID_CHILD);
+
+	/* unref for mlo ctxt taken at the start of this function */
+	dp_mlo_dev_ctxt_unref_delete(mlo_dev_ctxt, DP_MOD_ID_MLO_DEV);
+	dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * dp_mlo_dev_ctxt_vdev_detach() - Detach vdev from DP MLO dev context
+ * @soc_hdl: SOC handle
+ * @vdev_id: vdev id for the vdev to be attached
+ * @mld_mac_addr: MLD MAC address
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_vdev_detach(struct cdp_soc_t *soc_hdl,
+				       uint8_t vdev_id,
+				       uint8_t *mld_mac_addr)
+{
+	struct dp_vdev *vdev = NULL;
+	struct dp_vdev_be *be_vdev = NULL;
+	struct dp_mlo_dev_ctxt *mlo_dev_ctxt = NULL;
+	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
+	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
+
+	vdev = dp_vdev_get_ref_by_id(soc, vdev_id, DP_MOD_ID_CDP);
+	if (!vdev)
+		return QDF_STATUS_E_FAILURE;
+
+	be_vdev = dp_get_be_vdev_from_dp_vdev(vdev);
+
+	/* GET mlo_dev_ctxt from the global list */
+	mlo_dev_ctxt = dp_get_mlo_dev_ctx_by_mld_mac_addr(be_soc,
+							  mld_mac_addr,
+							  DP_MOD_ID_MLO_DEV);
+
+	if (!mlo_dev_ctxt) {
+		dp_err("Failed to get DP MLO Dev Context by MLD mac addr");
+		if (!be_vdev->mlo_dev_ctxt) {
+			dp_err("Failed to get DP MLO Dev Context from vdev");
+			dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP);
+			return QDF_STATUS_E_INVAL;
+		}
+		mlo_dev_ctxt = be_vdev->mlo_dev_ctxt;
+	}
+
+	dp_detach_vdev_list_in_mlo_dev_ctxt(be_soc, vdev, mlo_dev_ctxt);
+	be_vdev->mlo_dev_ctxt = NULL;
+
+	/* unref for mlo ctxt removed from be_vdev*/
+	dp_mlo_dev_ctxt_unref_delete(mlo_dev_ctxt, DP_MOD_ID_CHILD);
+
+	/* unref for mlo ctxt taken at the start of this function */
+	dp_mlo_dev_ctxt_unref_delete(mlo_dev_ctxt, DP_MOD_ID_MLO_DEV);
+
+	dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP);
+	return QDF_STATUS_SUCCESS;
+}
+#else
+void dp_mlo_dev_ctxt_list_attach(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+}
+
+void dp_mlo_dev_ctxt_list_detach(dp_mlo_dev_obj_t mlo_dev_obj)
+{
+}
+
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_create(struct cdp_soc_t *soc_hdl,
+				  uint8_t *mld_mac_addr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_destroy(struct cdp_soc_t *soc_hdl,
+				   uint8_t *mld_mac_addr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_vdev_attach(struct cdp_soc_t *soc_hdl,
+				       uint8_t vdev_id,
+				       uint8_t *mld_mac_addr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+QDF_STATUS dp_mlo_dev_ctxt_vdev_detach(struct cdp_soc_t *soc_hdl,
+				       uint8_t vdev_id,
+				       uint8_t *mld_mac_addr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_DP_MLO_DEV_CTX */
+
 #ifdef WLAN_FEATURE_11BE_MLO
 #ifdef WLAN_MCAST_MLO
 static inline void
@@ -2717,6 +3157,18 @@ dp_initialize_arch_ops_be_mlo(struct dp_arch_ops *arch_ops)
 }
 #endif /* WLAN_FEATURE_11BE_MLO */
 
+static struct cdp_cmn_mlo_ops dp_cmn_mlo_ops = {
+	.mlo_dev_ctxt_create = dp_mlo_dev_ctxt_create,
+	.mlo_dev_ctxt_attach = dp_mlo_dev_ctxt_vdev_attach,
+	.mlo_dev_ctxt_detach = dp_mlo_dev_ctxt_vdev_detach,
+	.mlo_dev_ctxt_destroy = dp_mlo_dev_ctxt_destroy,
+};
+
+void dp_soc_initialize_cdp_cmn_mlo_ops(struct dp_soc *soc)
+{
+	soc->cdp_soc.ops->cmn_mlo_ops = &dp_cmn_mlo_ops;
+}
+
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
 #define DP_LMAC_PEER_ID_MSB_LEGACY 2
 #define DP_LMAC_PEER_ID_MSB_MLO 3

+ 154 - 0
dp/wifi3.0/be/dp_be.h

@@ -315,6 +315,8 @@ struct dp_ppeds_napi {
  * @mlo_tstamp_offset: mlo timestamp offset
  * @mld_peer_hash_lock: lock to protect mld_peer_hash
  * @mld_peer_hash: peer hash table for ML peers
+ * @mlo_dev_list: list of MLO device context
+ * @mlo_dev_list_lock: lock to protect MLO device ctxt
  * @ipa_bank_id: TCL bank id used by IPA
  */
 struct dp_soc_be {
@@ -371,6 +373,10 @@ struct dp_soc_be {
 
 		TAILQ_HEAD(, dp_peer) * bins;
 	} mld_peer_hash;
+
+	/* MLO device ctxt list */
+	TAILQ_HEAD(, dp_mlo_dev_ctxt) mlo_dev_list;
+	qdf_spinlock_t mlo_dev_list_lock;
 #endif
 #endif
 #ifdef IPA_OFFLOAD
@@ -406,6 +412,7 @@ struct dp_pdev_be {
  * @mlo_stats: structure to hold stats for mlo unmapped peers
  * @seq_num: DP MLO seq number
  * @mcast_primary: MLO Mcast primary vdev
+ * @mlo_dev_ctxt: MLO device context pointer
  */
 struct dp_vdev_be {
 	struct dp_vdev vdev;
@@ -422,7 +429,44 @@ struct dp_vdev_be {
 #endif
 #endif
 #endif
+#ifdef WLAN_FEATURE_11BE_MLO
+	struct dp_mlo_dev_ctxt *mlo_dev_ctxt;
+#endif /* WLAN_FEATURE_11BE_MLO */
+};
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_DP_MLO_DEV_CTX)
+/**
+ * struct dp_mlo_dev_ctxt - Datapath MLO device context
+ *
+ * @ml_dev_list_elem: node in the ML dev list of Global MLO context
+ * @mld_mac_addr: MLO device MAC address
+ * @vdev_list: list of vdevs associated with this MLO connection
+ * @vdev_list_lock: lock to protect vdev list
+ * @bridge_vdev: list of bridge vdevs associated with this MLO connection
+ * @is_bridge_vdev_present: flag to check if bridge vdev is present
+ * @vdev_list_lock: lock to protect vdev list
+ * @vdev_count: number of elements in the vdev list
+ * @ref_cnt: reference count
+ * @mod_refs: module reference count
+ * @ref_delete_pending: flag to monitor last ref delete
+ * @stats: structure to store vdev stats of removed MLO Link
+ */
+struct dp_mlo_dev_ctxt {
+	TAILQ_ENTRY(dp_mlo_dev_ctxt) ml_dev_list_elem;
+	union dp_align_mac_addr mld_mac_addr;
+#ifdef WLAN_MLO_MULTI_CHIP
+	uint8_t vdev_list[WLAN_MAX_MLO_CHIPS][WLAN_MAX_MLO_LINKS_PER_SOC];
+	uint8_t bridge_vdev[WLAN_MAX_MLO_CHIPS][WLAN_MAX_MLO_LINKS_PER_SOC];
+	bool is_bridge_vdev_present;
+	qdf_spinlock_t vdev_list_lock;
+	uint16_t vdev_count;
+#endif
+	qdf_atomic_t ref_cnt;
+	qdf_atomic_t mod_refs[DP_MOD_ID_MAX];
+	uint8_t ref_delete_pending;
+	struct cdp_vdev_stats stats;
 };
+#endif /* WLAN_FEATURE_11BE_MLO */
 
 /**
  * struct dp_peer_be - Extended DP peer for BE targets
@@ -483,6 +527,7 @@ bool dp_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, dp_ptnr_soc_iter_func func,
 
 #ifdef WLAN_MLO_MULTI_CHIP
 typedef struct dp_mlo_ctxt *dp_mld_peer_hash_obj_t;
+typedef struct dp_mlo_ctxt *dp_mlo_dev_obj_t;
 
 /**
  * dp_mlo_get_peer_hash_obj() - return the container struct of MLO hash table
@@ -500,6 +545,17 @@ dp_mlo_get_peer_hash_obj(struct dp_soc *soc)
 
 void  dp_clr_mlo_ptnr_list(struct dp_soc *soc, struct dp_vdev *vdev);
 
+/**
+ * dp_get_mlo_dev_list_obj() - return the container struct of MLO Dev list
+ * @be_soc: be soc handle
+ *
+ * return: MLO dev list object
+ */
+static inline dp_mlo_dev_obj_t
+dp_get_mlo_dev_list_obj(struct dp_soc_be *be_soc)
+{
+	return be_soc->ml_ctxt;
+}
 #if defined(WLAN_FEATURE_11BE_MLO)
 /**
  * dp_mlo_partner_chips_map() - Map MLO peers to partner SOCs
@@ -521,6 +577,14 @@ void dp_mlo_partner_chips_map(struct dp_soc *soc,
 void dp_mlo_partner_chips_unmap(struct dp_soc *soc,
 				uint16_t peer_id);
 
+/**
+ * dp_soc_initialize_cdp_cmn_mlo_ops() - Initialize common CDP API's
+ * @soc: Soc handle
+ *
+ * Return: None
+ */
+void dp_soc_initialize_cdp_cmn_mlo_ops(struct dp_soc *soc);
+
 #ifdef WLAN_MLO_MULTI_CHIP
 typedef void dp_ptnr_vdev_iter_func(struct dp_vdev_be *be_vdev,
 				    struct dp_vdev *ptnr_vdev,
@@ -561,6 +625,7 @@ struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc,
 
 #else
 typedef struct dp_soc_be *dp_mld_peer_hash_obj_t;
+typedef struct dp_soc_be *dp_mlo_dev_obj_t;
 
 static inline dp_mld_peer_hash_obj_t
 dp_mlo_get_peer_hash_obj(struct dp_soc *soc)
@@ -572,6 +637,12 @@ static inline void  dp_clr_mlo_ptnr_list(struct dp_soc *soc,
 					 struct dp_vdev *vdev)
 {
 }
+
+static inline dp_mlo_dev_obj_t
+dp_get_mlo_dev_list_obj(struct dp_soc_be *be_soc)
+{
+	return be_soc;
+}
 #endif
 
 /**
@@ -893,4 +964,87 @@ void dp_mlo_update_link_to_pdev_unmap(struct dp_soc *soc, struct dp_pdev *pdev)
 {
 }
 #endif
+
+/**
+ * dp_mlo_dev_ctxt_list_attach_wrapper() - Wrapper API for MLO dev list Init
+ *
+ * @mlo_dev_obj: MLO device object
+ *
+ * Return: void
+ */
+void dp_mlo_dev_ctxt_list_attach_wrapper(dp_mlo_dev_obj_t mlo_dev_obj);
+
+/**
+ * dp_mlo_dev_ctxt_list_detach_wrapper() - Wrapper API for MLO dev list de-Init
+ *
+ * @mlo_dev_obj: MLO device object
+ *
+ * Return: void
+ */
+void dp_mlo_dev_ctxt_list_detach_wrapper(dp_mlo_dev_obj_t mlo_dev_obj);
+
+/**
+ * dp_mlo_dev_ctxt_list_attach() - API to initialize MLO device List
+ *
+ * @mlo_dev_obj: MLO device object
+ *
+ * Return: void
+ */
+void dp_mlo_dev_ctxt_list_attach(dp_mlo_dev_obj_t mlo_dev_obj);
+
+/**
+ * dp_mlo_dev_ctxt_list_detach() - API to de-initialize MLO device List
+ *
+ * @mlo_dev_obj: MLO device object
+ *
+ * Return: void
+ */
+void dp_mlo_dev_ctxt_list_detach(dp_mlo_dev_obj_t mlo_dev_obj);
+
+/**
+ * dp_soc_initialize_cdp_cmn_mlo_ops() - API to initialize common CDP MLO ops
+ *
+ * @soc: Datapath soc handle
+ *
+ * Return: void
+ */
+void dp_soc_initialize_cdp_cmn_mlo_ops(struct dp_soc *soc);
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_DP_MLO_DEV_CTX)
+/**
+ * dp_mlo_dev_ctxt_unref_delete() - Releasing the ref for MLO device ctxt
+ *
+ * @mlo_dev_ctxt: MLO device context handle
+ * @mod_id: module id which is releasing the reference
+ *
+ * Return: void
+ */
+void dp_mlo_dev_ctxt_unref_delete(struct dp_mlo_dev_ctxt *mlo_dev_ctxt,
+				  enum dp_mod_id mod_id);
+
+/**
+ * dp_mlo_dev_get_ref() - Get the ref for MLO device ctxt
+ *
+ * @mlo_dev_ctxt: MLO device context handle
+ * @mod_id: module id which is requesting the reference
+ *
+ * Return: SUCCESS on acquiring the ref.
+ */
+QDF_STATUS
+dp_mlo_dev_get_ref(struct dp_mlo_dev_ctxt *mlo_dev_ctxt,
+		   enum dp_mod_id mod_id);
+
+/**
+ * dp_get_mlo_dev_ctx_by_mld_mac_addr() - Get MLO device ctx based on MLD MAC
+ *
+ * @be_soc: be soc handle
+ * @mldaddr: MLD MAC address
+ * @mod_id: module id which is requesting the reference
+ *
+ * Return: MLO device context Handle on success, NULL on failure
+ */
+struct dp_mlo_dev_ctxt *
+dp_get_mlo_dev_ctx_by_mld_mac_addr(struct dp_soc_be *be_soc,
+				   uint8_t *mldaddr, enum dp_mod_id mod_id);
+#endif /* WLAN_DP_MLO_DEV_CTX */
 #endif

+ 2 - 0
dp/wifi3.0/be/mlo/dp_mlo.c

@@ -73,6 +73,7 @@ dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt)
 
 	qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock);
 	qdf_spinlock_create(&mlo_ctxt->grp_umac_reset_ctx.grp_ctx_lock);
+	dp_mlo_dev_ctxt_list_attach(mlo_ctxt);
 	return dp_mlo_ctx_to_cdp(mlo_ctxt);
 }
 
@@ -91,6 +92,7 @@ static void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt)
 
 	qdf_spinlock_destroy(&mlo_ctxt->grp_umac_reset_ctx.grp_ctx_lock);
 	qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock);
+	dp_mlo_dev_ctxt_list_detach(mlo_ctxt);
 	dp_mlo_peer_find_hash_detach_be(mlo_ctxt);
 	qdf_mem_free(mlo_ctxt);
 }

+ 5 - 0
dp/wifi3.0/be/mlo/dp_mlo.h

@@ -47,6 +47,8 @@
  * @rx_fst: pointer to rx_fst handle
  * @rx_fst_ref_cnt: ref count of rx_fst
  * @grp_umac_reset_ctx: UMAC reset context at mlo group level
+ * @mlo_dev_list: list of MLO device context
+ * @mlo_dev_list_lock: lock to protect MLO device ctxt
  */
 struct dp_mlo_ctxt {
 	struct cdp_ctrl_mlo_mgr *ctrl_ctxt;
@@ -68,6 +70,9 @@ struct dp_mlo_ctxt {
 #ifdef DP_UMAC_HW_RESET_SUPPORT
 	struct dp_soc_mlo_umac_reset_ctx grp_umac_reset_ctx;
 #endif
+	/* MLO device ctxt list */
+	TAILQ_HEAD(, dp_mlo_dev_ctxt) mlo_dev_list;
+	qdf_spinlock_t mlo_dev_list_lock;
 };
 
 /**

+ 2 - 0
dp/wifi3.0/dp_types.h

@@ -298,6 +298,7 @@ enum dp_peer_state {
  * @DP_MOD_ID_UMAC_RESET:
  * @DP_MOD_ID_TX_MCAST:
  * @DP_MOD_ID_DS:
+ * @DP_MOD_ID_MLO_DEV:
  * @DP_MOD_ID_MAX:
  */
 enum dp_mod_id {
@@ -331,6 +332,7 @@ enum dp_mod_id {
 	DP_MOD_ID_UMAC_RESET,
 	DP_MOD_ID_TX_MCAST,
 	DP_MOD_ID_DS,
+	DP_MOD_ID_MLO_DEV,
 	DP_MOD_ID_MAX,
 };