Преглед на файлове

qcacmn: cdp/dp peer change for MLO

cdp/dp peer change for MLO

Change-Id: I9b8eb741317a0dc7337aff7e773148892e531ba2
CRs-Fixed: 3031166
Jinwei Chen преди 3 години
родител
ревизия
5c85cfb5a0
променени са 10 файла, в които са добавени 1365 реда и са изтрити 239 реда
  1. 4 3
      dp/inc/cdp_txrx_cmn.h
  2. 25 0
      dp/inc/cdp_txrx_cmn_struct.h
  3. 3 2
      dp/inc/cdp_txrx_ops.h
  4. 0 5
      dp/wifi3.0/dp_internal.h
  5. 158 33
      dp/wifi3.0/dp_main.c
  6. 651 187
      dp/wifi3.0/dp_peer.c
  7. 463 0
      dp/wifi3.0/dp_peer.h
  8. 2 6
      dp/wifi3.0/dp_rx_defrag.c
  9. 1 1
      dp/wifi3.0/dp_rx_err.c
  10. 58 2
      dp/wifi3.0/dp_types.h

+ 4 - 3
dp/inc/cdp_txrx_cmn.h

@@ -373,11 +373,12 @@ static inline QDF_STATUS cdp_peer_create
 		return QDF_STATUS_E_FAILURE;
 
 	return soc->ops->cmn_drv_ops->txrx_peer_create(soc, vdev_id,
-			peer_mac_addr);
+			peer_mac_addr, CDP_LINK_PEER_TYPE);
 }
 
 static inline void cdp_peer_setup
-	(ol_txrx_soc_handle soc, uint8_t vdev_id, uint8_t *peer_mac)
+	(ol_txrx_soc_handle soc, uint8_t vdev_id, uint8_t *peer_mac,
+	 struct cdp_peer_setup_info *setup_info)
 {
 	if (!soc || !soc->ops) {
 		dp_cdp_debug("Invalid Instance:");
@@ -390,7 +391,7 @@ static inline void cdp_peer_setup
 		return;
 
 	soc->ops->cmn_drv_ops->txrx_peer_setup(soc, vdev_id,
-			peer_mac);
+			peer_mac, setup_info);
 }
 
 /*

+ 25 - 0
dp/inc/cdp_txrx_cmn_struct.h

@@ -385,6 +385,31 @@ enum htt_cmn_t2h_en_stats_status {
     HTT_CMN_T2H_EN_STATS_STATUS_SERIES_DONE         = 7,
 };
 
+/**
+ * enum cdp_peer_type - Peer type
+ * @CDP_INVALID_PEER_TYPE: invalid peer type
+ * @CDP_LINK_PEER_TYPE: legacy peer or link peer for MLO connection
+ * @CDP_MLD_PEER_TYPE: MLD peer for MLO connection
+ */
+enum cdp_peer_type {
+	CDP_INVALID_PEER_TYPE,
+	CDP_LINK_PEER_TYPE,
+	CDP_MLD_PEER_TYPE,
+};
+
+/**
+ * struct cdp_peer_setup_info: MLO connection info for cdp_peer_setup()
+ * @mld_peer_mac: mld peer mac address pointer
+ * @is_assoc_link: set true for first MLO link peer association
+ * @is_primary_link: for MCC, the first link will always be primary link,
+		     for WIN,  other link might be primary link.
+ */
+struct cdp_peer_setup_info {
+	uint8_t *mld_peer_mac;
+	uint8_t is_assoc_link:1,
+		is_primary_link:1;
+};
+
 /**
  * struct ol_txrx_peer_state - Peer state information
  */

+ 3 - 2
dp/inc/cdp_txrx_ops.h

@@ -156,11 +156,12 @@ struct cdp_cmn_ops {
 	QDF_STATUS
 	(*txrx_peer_create)
 		(ol_txrx_soc_handle soc, uint8_t vdev_id,
-		uint8_t *peer_mac_addr);
+		 uint8_t *peer_mac_addr, enum cdp_peer_type peer_type);
 
 	QDF_STATUS
 	(*txrx_peer_setup)(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
-			   uint8_t *peer_mac);
+			   uint8_t *peer_mac,
+			   struct cdp_peer_setup_info *setup_info);
 
 	QDF_STATUS
 	(*txrx_cp_peer_del_response)

+ 0 - 5
dp/wifi3.0/dp_internal.h

@@ -1543,11 +1543,6 @@ void dp_peer_ppdu_delayed_ba_cleanup(struct dp_peer *peer);
 extern void dp_peer_rx_init(struct dp_pdev *pdev, struct dp_peer *peer);
 void dp_peer_cleanup(struct dp_vdev *vdev, struct dp_peer *peer);
 void dp_peer_rx_cleanup(struct dp_vdev *vdev, struct dp_peer *peer);
-extern struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc,
-					      uint8_t *peer_mac_addr,
-					      int mac_addr_is_aligned,
-					      uint8_t vdev_id,
-					      enum dp_mod_id id);
 
 #ifdef DP_PEER_EXTENDED_API
 /**

+ 158 - 33
dp/wifi3.0/dp_main.c

@@ -214,7 +214,8 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc,
 	      struct ol_if_ops *ol_ops, uint16_t device_id);
 static inline QDF_STATUS dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl,
 					      uint8_t vdev_id,
-					      uint8_t *peer_mac_addr);
+					      uint8_t *peer_mac_addr,
+					      enum cdp_peer_type peer_type);
 static QDF_STATUS dp_peer_delete_wifi3(struct cdp_soc_t *soc_hdl,
 				       uint8_t vdev_id,
 				       uint8_t *peer_mac, uint32_t bitmap);
@@ -6037,7 +6038,7 @@ static QDF_STATUS dp_vdev_attach_wifi3(struct cdp_soc_t *cdp_soc,
 
 	if (wlan_op_mode_sta == vdev->opmode)
 		dp_peer_create_wifi3((struct cdp_soc_t *)soc, vdev_id,
-				     vdev->mac_addr.raw);
+				     vdev->mac_addr.raw, CDP_LINK_PEER_TYPE);
 	return QDF_STATUS_SUCCESS;
 
 fail0:
@@ -6137,19 +6138,9 @@ static QDF_STATUS dp_vdev_register_wifi3(struct cdp_soc_t *soc_hdl,
 	return QDF_STATUS_SUCCESS;
 }
 
-/**
- * dp_peer_delete() - delete DP peer
- *
- * @soc: Datatpath soc
- * @peer: Datapath peer
- * @arg: argument to iter function
- *
- * Return: void
- */
-static void
-dp_peer_delete(struct dp_soc *soc,
-	       struct dp_peer *peer,
-	       void *arg)
+void dp_peer_delete(struct dp_soc *soc,
+		    struct dp_peer *peer,
+		    void *arg)
 {
 	if (!peer->valid)
 		return;
@@ -6293,8 +6284,49 @@ static QDF_STATUS dp_vdev_detach_wifi3(struct cdp_soc_t *cdp_soc,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * is_dp_peer_can_reuse() - check if the dp_peer match condition to be reused
+ * @vdev: Target DP vdev handle
+ * @peer: DP peer handle to be checked
+ * @peer_mac_addr: Target peer mac address
+ * @peer_type: Target peer type
+ *
+ * Return: true - if match, false - not match
+ */
+static inline
+bool is_dp_peer_can_reuse(struct dp_vdev *vdev,
+			  struct dp_peer *peer,
+			  uint8_t *peer_mac_addr,
+			  enum cdp_peer_type peer_type)
+{
+	if (peer->bss_peer && (peer->vdev == vdev) &&
+	    (peer->peer_type == peer_type) &&
+	    (qdf_mem_cmp(peer_mac_addr, peer->mac_addr.raw,
+			 QDF_MAC_ADDR_SIZE) == 0))
+		return true;
+
+	return false;
+}
+#else
+static inline
+bool is_dp_peer_can_reuse(struct dp_vdev *vdev,
+			  struct dp_peer *peer,
+			  uint8_t *peer_mac_addr,
+			  enum cdp_peer_type peer_type)
+{
+	if (peer->bss_peer && (peer->vdev == vdev) &&
+	    (qdf_mem_cmp(peer_mac_addr, peer->mac_addr.raw,
+			 QDF_MAC_ADDR_SIZE) == 0))
+		return true;
+
+	return false;
+}
+#endif
+
 static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev,
-						uint8_t *peer_mac_addr)
+						uint8_t *peer_mac_addr,
+						enum cdp_peer_type peer_type)
 {
 	struct dp_peer *peer;
 	struct dp_soc *soc = vdev->pdev->soc;
@@ -6304,9 +6336,8 @@ static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev,
 		      inactive_list_elem) {
 
 		/* reuse bss peer only when vdev matches*/
-		if (peer->bss_peer && (peer->vdev == vdev) &&
-		    qdf_mem_cmp(peer_mac_addr, peer->mac_addr.raw,
-				QDF_MAC_ADDR_SIZE) == 0) {
+		if (is_dp_peer_can_reuse(vdev, peer,
+					 peer_mac_addr, peer_type)) {
 			/* increment ref count for cdp_peer_create*/
 			if (dp_peer_get_ref(soc, peer, DP_MOD_ID_CONFIG) ==
 						QDF_STATUS_SUCCESS) {
@@ -6365,12 +6396,13 @@ static inline void dp_peer_rx_bufq_resources_init(struct dp_peer *peer)
  * @soc_hdl: Datapath soc handle
  * @vdev_id: id of vdev
  * @peer_mac_addr: Peer MAC address
+ * @peer_type: link or MLD peer type
  *
  * Return: 0 on success, -1 on failure
  */
 static QDF_STATUS
 dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
-		     uint8_t *peer_mac_addr)
+		     uint8_t *peer_mac_addr, enum cdp_peer_type peer_type)
 {
 	struct dp_peer *peer;
 	int i;
@@ -6395,17 +6427,18 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
 	 * If a peer entry with given MAC address already exists,
 	 * reuse the peer and reset the state of peer.
 	 */
-	peer = dp_peer_can_reuse(vdev, peer_mac_addr);
+	peer = dp_peer_can_reuse(vdev, peer_mac_addr, peer_type);
 
 	if (peer) {
-		dp_peer_vdev_list_add(soc, vdev, peer);
-
-		dp_peer_find_hash_add(soc, peer);
 		qdf_atomic_init(&peer->is_default_route_set);
 		dp_peer_cleanup(vdev, peer);
 
-		for (i = 0; i < DP_MAX_TIDS; i++)
-			qdf_spinlock_create(&peer->rx_tid[i].tid_lock);
+		dp_peer_vdev_list_add(soc, vdev, peer);
+		dp_peer_find_hash_add(soc, peer);
+
+		dp_peer_rx_tids_create(peer);
+		if (IS_MLO_DP_MLD_PEER(peer))
+			dp_mld_peer_init_link_peers_info(peer);
 
 		qdf_spin_lock_bh(&soc->ast_lock);
 		dp_peer_delete_ast_entries(soc, peer);
@@ -6474,6 +6507,7 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
 
 	/* store provided params */
 	peer->vdev = vdev;
+	DP_PEER_SET_TYPE(peer, peer_type);
 	/* get the vdev reference for new peer */
 	dp_vdev_get_ref(soc, vdev, DP_MOD_ID_CHILD);
 
@@ -6534,8 +6568,9 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
 		peer->sta_self_peer = 1;
 	}
 
-	for (i = 0; i < DP_MAX_TIDS; i++)
-		qdf_spinlock_create(&peer->rx_tid[i].tid_lock);
+	dp_peer_rx_tids_create(peer);
+	if (IS_MLO_DP_MLD_PEER(peer))
+		dp_mld_peer_init_link_peers_info(peer);
 
 	peer->valid = 1;
 	dp_local_peer_id_alloc(pdev, peer);
@@ -6584,6 +6619,90 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+QDF_STATUS dp_peer_mlo_setup(
+			struct dp_soc *soc,
+			struct dp_peer *peer,
+			uint8_t vdev_id,
+			struct cdp_peer_setup_info *setup_info)
+{
+	struct dp_peer *mld_peer = NULL;
+
+	/* Non-MLO connection, do nothing */
+	if (!setup_info || !setup_info->mld_peer_mac)
+		return QDF_STATUS_SUCCESS;
+
+	/* To do: remove this check if link/mld peer mac_addr allow to same */
+	if (!qdf_mem_cmp(setup_info->mld_peer_mac, peer->mac_addr.raw,
+			 QDF_MAC_ADDR_SIZE)) {
+		dp_peer_err("Same mac addres for link/mld peer");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* if this is the first assoc link */
+	if (setup_info->is_assoc_link)
+		/* create MLD peer */
+		dp_peer_create_wifi3((struct cdp_soc_t *)soc,
+				     vdev_id,
+				     setup_info->mld_peer_mac,
+				     CDP_MLD_PEER_TYPE);
+
+	peer->assoc_link = setup_info->is_assoc_link;
+	peer->primary_link = setup_info->is_primary_link;
+	mld_peer = dp_peer_find_hash_find(soc,
+					  setup_info->mld_peer_mac,
+					  0, DP_VDEV_ALL, DP_MOD_ID_CDP);
+	if (mld_peer) {
+		if (setup_info->is_assoc_link) {
+			/* assign rx_tid to mld peer */
+			mld_peer->rx_tid = peer->rx_tid;
+			/* no cdp_peer_setup for MLD peer,
+			 * set it for addba processing
+			 */
+			qdf_atomic_set(&mld_peer->is_default_route_set, 1);
+		} else {
+			/* free link peer origial rx_tids mem */
+			dp_peer_rx_tids_destroy(peer);
+			/* assign mld peer rx_tid to link peer */
+			peer->rx_tid = mld_peer->rx_tid;
+		}
+
+		if (setup_info->is_primary_link &&
+		    !setup_info->is_assoc_link) {
+			/*
+			 * if first link is not the primary link,
+			 * then need to change mld_peer->vdev as
+			 * primary link dp_vdev is not same one
+			 * during mld peer creation.
+			 */
+
+			/* relase the ref to original dp_vdev */
+			dp_vdev_unref_delete(soc, mld_peer->vdev,
+					     DP_MOD_ID_CDP);
+			/*
+			 * get the ref to new dp_vdev,
+			 * increase dp_vdev ref_cnt
+			 */
+			mld_peer->vdev = dp_vdev_get_ref_by_id(soc, vdev_id,
+							       DP_MOD_ID_CDP);
+		}
+
+		/* associate mld and link peer */
+		dp_link_peer_add_mld_peer(peer, mld_peer);
+		dp_mld_peer_add_link_peer(mld_peer, peer);
+
+		dp_peer_unref_delete(mld_peer, DP_MOD_ID_CDP);
+	} else {
+		peer->mld_peer = NULL;
+		dp_err("mld peer" QDF_MAC_ADDR_FMT "not found!",
+		       QDF_MAC_ADDR_REF(setup_info->mld_peer_mac));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /*
  * dp_vdev_get_default_reo_hash() - get reo dest ring and hash values for a vdev
  * @vdev: Datapath VDEV handle
@@ -6707,12 +6826,14 @@ static void dp_peer_setup_get_reo_hash(struct dp_vdev *vdev,
  * @soc_hdl: soc handle object
  * @vdev_id : vdev_id of vdev object
  * @peer_mac: Peer's mac address
+ * @peer_setup_info: peer setup info for MLO
  *
  * Return: QDF_STATUS
  */
 static QDF_STATUS
 dp_peer_setup_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
-		    uint8_t *peer_mac)
+		    uint8_t *peer_mac,
+		    struct cdp_peer_setup_info *setup_info)
 {
 	struct dp_soc *soc = (struct dp_soc *)soc_hdl;
 	struct dp_pdev *pdev;
@@ -6767,6 +6888,12 @@ dp_peer_setup_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
 
 	qdf_atomic_set(&peer->is_default_route_set, 1);
 
+	status = dp_peer_mlo_setup(soc, peer, vdev->vdev_id, setup_info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_peer_err("peer mlo setup failed");
+		qdf_assert_always(0);
+	}
+
 	if (vdev_opmode != wlan_op_mode_monitor)
 		dp_peer_rx_init(pdev, peer);
 
@@ -7275,7 +7402,6 @@ void dp_peer_unref_delete(struct dp_peer *peer, enum dp_mod_id mod_id)
 	struct cdp_peer_cookie peer_cookie;
 	struct dp_peer *tmp_peer;
 	bool found = false;
-	int tid = 0;
 
 	if (mod_id > DP_MOD_ID_RX)
 		QDF_ASSERT(qdf_atomic_dec_return(&peer->mod_refs[mod_id]) >= 0);
@@ -7345,9 +7471,6 @@ void dp_peer_unref_delete(struct dp_peer *peer, enum dp_mod_id mod_id)
 		dp_peer_cleanup(vdev, peer);
 		dp_monitor_peer_detach(soc, peer);
 
-		for (tid = 0; tid < DP_MAX_TIDS; tid++)
-			qdf_spinlock_destroy(&peer->rx_tid[tid].tid_lock);
-
 		qdf_spinlock_destroy(&peer->peer_state_lock);
 		qdf_mem_free(peer);
 
@@ -7428,6 +7551,8 @@ static QDF_STATUS dp_peer_delete_wifi3(struct cdp_soc_t *soc_hdl,
 
 	dp_peer_vdev_list_remove(soc, vdev, peer);
 
+	dp_peer_mlo_delete(soc, peer);
+
 	qdf_spin_lock_bh(&soc->inactive_peer_list_lock);
 	TAILQ_INSERT_TAIL(&soc->inactive_peer_list, peer,
 			  inactive_list_elem);

Файловите разлики са ограничени, защото са твърде много
+ 651 - 187
dp/wifi3.0/dp_peer.c


+ 463 - 0
dp/wifi3.0/dp_peer.h

@@ -62,6 +62,11 @@ struct ast_del_ctxt {
 typedef void dp_peer_iter_func(struct dp_soc *soc, struct dp_peer *peer,
 			       void *arg);
 void dp_peer_unref_delete(struct dp_peer *peer, enum dp_mod_id id);
+struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc,
+				       uint8_t *peer_mac_addr,
+				       int mac_addr_is_aligned,
+				       uint8_t vdev_id,
+				       enum dp_mod_id id);
 
 /**
  * dp_peer_get_ref() - Returns peer object given the peer id
@@ -968,4 +973,462 @@ static inline void dp_get_rx_reo_queue_info(
 {
 }
 #endif /* DUMP_REO_QUEUE_INFO_IN_DDR */
+
+static inline int dp_peer_find_mac_addr_cmp(
+	union dp_align_mac_addr *mac_addr1,
+	union dp_align_mac_addr *mac_addr2)
+{
+		/*
+		 * Intentionally use & rather than &&.
+		 * because the operands are binary rather than generic boolean,
+		 * the functionality is equivalent.
+		 * Using && has the advantage of short-circuited evaluation,
+		 * but using & has the advantage of no conditional branching,
+		 * which is a more significant benefit.
+		 */
+	return !((mac_addr1->align4.bytes_abcd == mac_addr2->align4.bytes_abcd)
+		 & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef));
+}
+
+/**
+ * dp_peer_delete() - delete DP peer
+ *
+ * @soc: Datatpath soc
+ * @peer: Datapath peer
+ * @arg: argument to iter function
+ *
+ * Return: void
+ */
+void dp_peer_delete(struct dp_soc *soc,
+		    struct dp_peer *peer,
+		    void *arg);
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/* set peer type */
+#define DP_PEER_SET_TYPE(_peer, _type_val) \
+	((_peer)->peer_type = (_type_val))
+/* is MLO connection link peer */
+#define IS_MLO_DP_LINK_PEER(_peer) \
+	((_peer)->peer_type == CDP_LINK_PEER_TYPE && (_peer)->mld_peer)
+/* is MLO connection mld peer */
+#define IS_MLO_DP_MLD_PEER(_peer) \
+	((_peer)->peer_type == CDP_MLD_PEER_TYPE)
+
+/**
+ * dp_link_peer_add_mld_peer() - add mld peer pointer to link peer,
+				 increase mld peer ref_cnt
+ * @link_peer: link peer pointer
+ * @mld_peer: mld peer pointer
+ *
+ * Return: none
+ */
+static inline
+void dp_link_peer_add_mld_peer(struct dp_peer *link_peer,
+			       struct dp_peer *mld_peer)
+{
+	/* increase mld_peer ref_cnt */
+	dp_peer_get_ref(NULL, mld_peer, DP_MOD_ID_CDP);
+	link_peer->mld_peer = mld_peer;
+}
+
+/**
+ * dp_link_peer_del_mld_peer() - delete mld peer pointer from link peer,
+				 decrease mld peer ref_cnt
+ * @link_peer: link peer pointer
+ *
+ * Return: None
+ */
+static inline
+void dp_link_peer_del_mld_peer(struct dp_peer *link_peer)
+{
+	dp_peer_unref_delete(link_peer->mld_peer, DP_MOD_ID_CDP);
+	link_peer->mld_peer = NULL;
+}
+
+/**
+ * dp_mld_peer_init_link_peers_info() - init link peers info in mld peer
+ * @mld_peer: mld peer pointer
+ *
+ * Return: None
+ */
+static inline
+void dp_mld_peer_init_link_peers_info(struct dp_peer *mld_peer)
+{
+	int i;
+
+	qdf_spinlock_create(&mld_peer->link_peers_info_lock);
+	mld_peer->num_links = 0;
+	for (i = 0; i < DP_MAX_MLO_LINKS; i++)
+		mld_peer->link_peers[i].is_valid = false;
+}
+
+/**
+ * dp_mld_peer_deinit_link_peers_info() - Deinit link peers info in mld peer
+ * @mld_peer: mld peer pointer
+ *
+ * Return: None
+ */
+static inline
+void dp_mld_peer_deinit_link_peers_info(struct dp_peer *mld_peer)
+{
+	qdf_spinlock_destroy(&mld_peer->link_peers_info_lock);
+}
+
+/**
+ * dp_mld_peer_add_link_peer() - add link peer info to mld peer
+ * @mld_peer: mld dp peer pointer
+ * @link_peer: link dp peer pointer
+ *
+ * Return: None
+ */
+static inline
+void dp_mld_peer_add_link_peer(struct dp_peer *mld_peer,
+			       struct dp_peer *link_peer)
+{
+	int i;
+	struct dp_peer_link_info *link_peer_info;
+
+	qdf_spin_lock_bh(&mld_peer->link_peers_info_lock);
+	for (i = 0; i < DP_MAX_MLO_LINKS; i++) {
+		link_peer_info = &mld_peer->link_peers[i];
+		if (!link_peer_info->is_valid) {
+			qdf_mem_copy(link_peer_info->mac_addr.raw,
+				     link_peer->mac_addr.raw,
+				     QDF_MAC_ADDR_SIZE);
+			link_peer_info->is_valid = true;
+			link_peer_info->vdev_id = link_peer->vdev->vdev_id;
+			mld_peer->num_links++;
+			break;
+		}
+	}
+	qdf_spin_unlock_bh(&mld_peer->link_peers_info_lock);
+
+	if (i == DP_MAX_MLO_LINKS)
+		dp_err("fail to add link peer" QDF_MAC_ADDR_FMT "to mld peer",
+		       QDF_MAC_ADDR_REF(link_peer->mac_addr.raw));
+}
+
+/**
+ * dp_mld_peer_del_link_peer() - Delete link peer info from MLD peer
+ * @mld_peer: MLD dp peer pointer
+ * @link_peer: link dp peer pointer
+ *
+ * Return: number of links left after deletion
+ */
+static inline
+uint8_t dp_mld_peer_del_link_peer(struct dp_peer *mld_peer,
+				  struct dp_peer *link_peer)
+{
+	int i;
+	struct dp_peer_link_info *link_peer_info;
+	uint8_t num_links;
+
+	qdf_spin_lock_bh(&mld_peer->link_peers_info_lock);
+	for (i = 0; i < DP_MAX_MLO_LINKS; i++) {
+		link_peer_info = &mld_peer->link_peers[i];
+		if (link_peer_info->is_valid &&
+		    !dp_peer_find_mac_addr_cmp(&link_peer->mac_addr,
+					&link_peer_info->mac_addr)) {
+			link_peer_info->is_valid = false;
+			mld_peer->num_links--;
+			break;
+		}
+	}
+	num_links = mld_peer->num_links;
+	qdf_spin_unlock_bh(&mld_peer->link_peers_info_lock);
+
+	if (i == DP_MAX_MLO_LINKS)
+		dp_err("fail to del link peer" QDF_MAC_ADDR_FMT "to mld peer",
+		       QDF_MAC_ADDR_REF(link_peer->mac_addr.raw));
+
+	return num_links;
+}
+
+/**
+ * dp_get_link_peers_ref_from_mld_peer() - get link peers pointer and
+					   increase link peers ref_cnt
+ * @soc: dp_soc handle
+ * @mld_peer: dp mld peer pointer
+ * @mld_link_peers: structure that hold links peers ponter array and number
+ * @mod_id: id of module requesting reference
+ *
+ * Return: None
+ */
+static inline
+void dp_get_link_peers_ref_from_mld_peer(
+				struct dp_soc *soc,
+				struct dp_peer *mld_peer,
+				struct dp_mld_link_peers *mld_link_peers,
+				enum dp_mod_id mod_id)
+{
+	struct dp_peer *peer;
+	uint8_t i = 0, j = 0;
+	struct dp_peer_link_info *link_peer_info;
+
+	qdf_mem_zero(mld_link_peers, sizeof(*mld_link_peers));
+	qdf_spin_lock_bh(&mld_peer->link_peers_info_lock);
+	for (i = 0; i < DP_MAX_MLO_LINKS; i++)  {
+		link_peer_info = &mld_peer->link_peers[i];
+		if (link_peer_info->is_valid) {
+			peer = dp_peer_find_hash_find(
+						soc,
+						link_peer_info->mac_addr.raw,
+						true,
+						link_peer_info->vdev_id,
+						mod_id);
+			if (peer)
+				mld_link_peers->link_peers[j++] = peer;
+		}
+	}
+	qdf_spin_unlock_bh(&mld_peer->link_peers_info_lock);
+
+	mld_link_peers->num_links = j;
+}
+
+/**
+ * dp_release_link_peers_ref() - release all link peers reference
+ * @mld_link_peers: structure that hold links peers ponter array and number
+ * @mod_id: id of module requesting reference
+ *
+ * Return: None.
+ */
+static inline
+void dp_release_link_peers_ref(
+			struct dp_mld_link_peers *mld_link_peers,
+			enum dp_mod_id mod_id)
+{
+	struct dp_peer *peer;
+	uint8_t i;
+
+	for (i = 0; i < mld_link_peers->num_links; i++) {
+		peer = mld_link_peers->link_peers[i];
+		if (peer)
+			dp_peer_unref_delete(peer, mod_id);
+		mld_link_peers->link_peers[i] = NULL;
+	}
+
+	 mld_link_peers->num_links = 0;
+}
+
+/**
+ * dp_peer_get_tgt_peer_hash_find() - get MLD dp_peer handle
+				   for processing
+ * @soc: soc handle
+ * @peer_mac_addr: peer mac address
+ * @mac_addr_is_aligned: is mac addr alligned
+ * @vdev_id: vdev_id
+ * @mod_id: id of module requesting reference
+ *
+ * for MLO connection, get corresponding MLD peer,
+ * otherwise get link peer for non-MLO case.
+ *
+ * return: peer in success
+ *         NULL in failure
+ */
+static inline
+struct dp_peer *dp_peer_get_tgt_peer_hash_find(struct dp_soc *soc,
+					       uint8_t *peer_mac,
+					       int mac_addr_is_aligned,
+					       uint8_t vdev_id,
+					       enum dp_mod_id mod_id)
+{
+	struct dp_peer *ta_peer = NULL;
+	struct dp_peer *peer = dp_peer_find_hash_find(soc,
+						      peer_mac, 0, vdev_id,
+						      mod_id);
+
+	if (peer) {
+		/* mlo connection link peer, get mld peer with reference */
+		if (IS_MLO_DP_LINK_PEER(peer)) {
+			/* increase mld peer ref_cnt */
+			if (QDF_STATUS_SUCCESS ==
+			    dp_peer_get_ref(soc, peer->mld_peer, mod_id))
+				ta_peer = peer->mld_peer;
+			else
+				ta_peer = NULL;
+
+			/* relese peer reference that added by hash find */
+			dp_peer_unref_delete(peer, mod_id);
+		} else {
+		/* mlo MLD peer or non-mlo link peer */
+			ta_peer = peer;
+		}
+	}
+
+	return ta_peer;
+}
+
+/**
+ * dp_peer_get_tgt_peer_by_id() - Returns target peer object given the peer id
+ * @soc		: core DP soc context
+ * @peer_id	: peer id from peer object can be retrieved
+ * @mod_id      : ID ot module requesting reference
+ *
+ * for MLO connection, get corresponding MLD peer,
+ * otherwise get link peer for non-MLO case.
+ *
+ * return: peer in success
+ *         NULL in failure
+ */
+static inline
+struct dp_peer *dp_peer_get_tgt_peer_by_id(struct dp_soc *soc,
+					   uint16_t peer_id,
+					   enum dp_mod_id mod_id)
+{
+	struct dp_peer *ta_peer = NULL;
+	struct dp_peer *peer = dp_peer_get_ref_by_id(soc, peer_id, mod_id);
+
+	if (peer) {
+		/* mlo connection link peer, get mld peer with reference */
+		if (IS_MLO_DP_LINK_PEER(peer)) {
+			/* increase mld peer ref_cnt */
+			if (QDF_STATUS_SUCCESS ==
+				dp_peer_get_ref(soc, peer->mld_peer, mod_id))
+				ta_peer = peer->mld_peer;
+			else
+				ta_peer = NULL;
+
+			/* relese peer reference that added by hash find */
+			dp_peer_unref_delete(peer, mod_id);
+		} else {
+		/* mlo MLD peer or non-mlo link peer */
+			ta_peer = peer;
+		}
+	}
+
+	return ta_peer;
+}
+
+/**
+ * dp_peer_mlo_delete() - peer MLO related delete operation
+ * @soc: Soc handle
+ * @peer: DP peer handle
+ * Return: None
+ */
+static inline
+void dp_peer_mlo_delete(struct dp_soc *soc,
+			struct dp_peer *peer)
+{
+	/* MLO connection link peer */
+	if (IS_MLO_DP_LINK_PEER(peer)) {
+		/* if last link peer deletion, delete MLD peer */
+		if (dp_mld_peer_del_link_peer(peer->mld_peer, peer) == 0)
+			dp_peer_delete(soc, peer->mld_peer, NULL);
+	}
+}
+
+/**
+ * dp_peer_mlo_setup() - create MLD peer and MLO related initialization
+ * @soc: Soc handle
+ * @vdev_id: Vdev ID
+ * @peer_setup_info: peer setup information for MLO
+ */
+QDF_STATUS dp_peer_mlo_setup(
+			struct dp_soc *soc,
+			struct dp_peer *peer,
+			uint8_t vdev_id,
+			struct cdp_peer_setup_info *setup_info);
+#else
+#define DP_PEER_SET_TYPE(_peer, _type_val) /* no op */
+#define IS_MLO_DP_LINK_PEER(_peer) false
+#define IS_MLO_DP_MLD_PEER(_peer) false
+
+static inline
+struct dp_peer *dp_peer_get_tgt_peer_hash_find(struct dp_soc *soc,
+					       uint8_t *peer_mac,
+					       int mac_addr_is_aligned,
+					       uint8_t vdev_id,
+					       enum dp_mod_id mod_id)
+{
+	return dp_peer_find_hash_find(soc, peer_mac,
+				      mac_addr_is_aligned, vdev_id,
+				      mod_id);
+}
+
+static inline
+struct dp_peer *dp_peer_get_tgt_peer_by_id(struct dp_soc *soc,
+					   uint16_t peer_id,
+					   enum dp_mod_id mod_id)
+{
+	return dp_peer_get_ref_by_id(soc, peer_id, mod_id);
+}
+
+static inline
+QDF_STATUS dp_peer_mlo_setup(
+			struct dp_soc *soc,
+			struct dp_peer *peer,
+			uint8_t vdev_id,
+			struct cdp_peer_setup_info *setup_info)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+void dp_mld_peer_init_link_peers_info(struct dp_peer *mld_peer)
+{
+}
+
+static inline
+void dp_mld_peer_deinit_link_peers_info(struct dp_peer *mld_peer)
+{
+}
+
+static inline
+void dp_link_peer_del_mld_peer(struct dp_peer *link_peer)
+{
+}
+
+static inline
+void dp_peer_mlo_delete(struct dp_soc *soc,
+			struct dp_peer *peer)
+{
+}
+#endif /* WLAN_FEATURE_11BE_MLO */
+
+static inline
+QDF_STATUS dp_peer_rx_tids_create(struct dp_peer *peer)
+{
+	uint8_t i;
+
+	if (IS_MLO_DP_MLD_PEER(peer)) {
+		dp_peer_info("skip for mld peer");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (peer->rx_tid) {
+		QDF_BUG(0);
+		dp_peer_err("peer rx_tid mem already exist");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	peer->rx_tid = qdf_mem_malloc(DP_MAX_TIDS *
+				      sizeof(struct dp_rx_tid));
+
+	if (!peer->rx_tid) {
+		dp_err("fail to alloc tid for peer" QDF_MAC_ADDR_FMT,
+		       QDF_MAC_ADDR_REF(peer->mac_addr.raw));
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_mem_zero(peer->rx_tid, DP_MAX_TIDS * sizeof(struct dp_rx_tid));
+	for (i = 0; i < DP_MAX_TIDS; i++)
+		qdf_spinlock_create(&peer->rx_tid[i].tid_lock);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+void dp_peer_rx_tids_destroy(struct dp_peer *peer)
+{
+	uint8_t i;
+
+	if (!IS_MLO_DP_LINK_PEER(peer)) {
+		for (i = 0; i < DP_MAX_TIDS; i++)
+			qdf_spinlock_destroy(&peer->rx_tid[i].tid_lock);
+
+		qdf_mem_free(peer->rx_tid);
+	}
+
+	peer->rx_tid = NULL;
+}
 #endif /* _DP_PEER_H_ */

+ 2 - 6
dp/wifi3.0/dp_rx_defrag.c

@@ -222,9 +222,7 @@ void dp_rx_defrag_waitlist_flush(struct dp_soc *soc)
 		TAILQ_REMOVE(&temp_list, rx_reorder,
 			     defrag_waitlist_elem);
 		/* get address of current peer */
-		peer =
-			container_of(rx_reorder, struct dp_peer,
-				     rx_tid[rx_reorder->tid]);
+		peer = rx_reorder->defrag_peer;
 		qdf_spin_unlock_bh(&rx_reorder->tid_lock);
 
 		temp_peer = dp_peer_get_ref_by_id(soc, peer->peer_id,
@@ -298,9 +296,7 @@ void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid)
 		struct dp_peer *peer_on_waitlist;
 
 		/* get address of current peer */
-		peer_on_waitlist =
-			container_of(rx_reorder, struct dp_peer,
-				     rx_tid[rx_reorder->tid]);
+		peer_on_waitlist = rx_reorder->defrag_peer;
 
 		/* Ensure it is TID for same peer */
 		if (peer_on_waitlist == peer && rx_reorder->tid == tid) {

+ 1 - 1
dp/wifi3.0/dp_rx_err.c

@@ -628,7 +628,7 @@ _dp_rx_bar_frame_handle(struct dp_soc *soc, qdf_nbuf_t nbuf,
 	struct dp_peer *peer;
 
 	peer_id = DP_PEER_METADATA_PEER_ID_GET(mpdu_desc_info->peer_meta_data);
-	peer = dp_peer_get_ref_by_id(soc, peer_id, DP_MOD_ID_RX_ERR);
+	peer = dp_peer_get_tgt_peer_by_id(soc, peer_id, DP_MOD_ID_RX_ERR);
 	if (!peer)
 		return;
 

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

@@ -810,6 +810,9 @@ struct dp_rx_tid {
 
 	/* Peer TID statistics */
 	struct cdp_peer_tid_stats stats;
+
+	/* defrag usage only, dp_peer pointer related with this tid */
+	struct dp_peer *defrag_peer;
 };
 
 /**
@@ -1905,6 +1908,15 @@ struct dp_soc {
 		TAILQ_HEAD(, dp_peer) * bins;
 	} peer_hash;
 
+#ifdef WLAN_FEATURE_11BE_MLO
+	/* Protect mld peer hash table */
+	DP_MUTEX_TYPE mld_peer_hash_lock;
+	struct {
+		unsigned mask;
+		unsigned idx_bits;
+		TAILQ_HEAD(, dp_peer) * bins;
+	} mld_peer_hash;
+#endif
 	/* rx defrag state – TBD: do we need this per radio? */
 	struct {
 		struct {
@@ -3122,6 +3134,34 @@ struct dp_peer_mesh_latency_parameter {
 };
 #endif
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/* Max number of links for MLO connection */
+#define DP_MAX_MLO_LINKS 3
+
+/**
+ * struct dp_peer_link_info - link peer information for MLO
+ * @mac_add: Mac address
+ * @vdev_id: Vdev ID for current link peer
+ * @is_valid: flag for link peer info valid or not
+ */
+struct dp_peer_link_info {
+	union dp_align_mac_addr mac_addr;
+	uint8_t vdev_id;
+	uint8_t is_valid;
+};
+
+/**
+ * struct dp_mld_link_peers - this structure is used to get link peers
+			      pointer from mld peer
+ * @link_peers: link peers pointer array
+ * @num_links: number of link peers fetched
+ */
+struct dp_mld_link_peers {
+	struct dp_peer *link_peers[DP_MAX_MLO_LINKS];
+	uint8_t num_links;
+};
+#endif
+
 /* Peer structure for data path state */
 struct dp_peer {
 	/* VDEV to which this peer is associated */
@@ -3141,8 +3181,8 @@ struct dp_peer {
 	/* node in the hash table bin's list of peers */
 	TAILQ_ENTRY(dp_peer) hash_list_elem;
 
-	/* TID structures */
-	struct dp_rx_tid rx_tid[DP_MAX_TIDS];
+	/* TID structures pointer */
+	struct dp_rx_tid *rx_tid;
 
 	/* TBD: No transmit TID state required? */
 
@@ -3164,6 +3204,11 @@ struct dp_peer {
 		delete_in_progress:1, /* Indicate kickout sent */
 		sta_self_peer:1; /* Indicate STA self peer */
 
+#ifdef WLAN_FEATURE_11BE_MLO
+	uint8_t assoc_link:1, /* first assoc link peer for MLO */
+		primary_link:1; /* primary link for MLO */
+#endif
+
 #ifdef QCA_SUPPORT_PEER_ISOLATION
 	bool isolation; /* enable peer isolation for this peer */
 #endif
@@ -3248,6 +3293,17 @@ struct dp_peer {
 #ifdef WIFI_MONITOR_SUPPORT
 	struct dp_mon_peer *monitor_peer;
 #endif
+#ifdef WLAN_FEATURE_11BE_MLO
+	/* peer type */
+	enum cdp_peer_type peer_type;
+	/*---------for link peer---------*/
+	struct dp_peer *mld_peer;
+
+	/*---------for mld peer----------*/
+	struct dp_peer_link_info link_peers[DP_MAX_MLO_LINKS];
+	uint8_t num_links;
+	DP_MUTEX_TYPE link_peers_info_lock;
+#endif
 };
 
 /*

Някои файлове не бяха показани, защото твърде много файлове са промени