xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/be/mlo/dp_mlo.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <wlan_utility.h>
17 #include <dp_internal.h>
18 #include <dp_htt.h>
19 #include <hal_be_api.h>
20 #include "dp_mlo.h"
21 #include <dp_be.h>
22 #include <dp_htt.h>
23 #include <dp_internal.h>
24 #include <wlan_cfg.h>
25 #include <wlan_mlo_mgr_cmn.h>
26 /*
27  * dp_mlo_ctxt_attach_wifi3 () – Attach DP MLO context
28  *
29  * Return: DP MLO context handle on success, NULL on failure
30  */
31 struct cdp_mlo_ctxt *
32 dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt)
33 {
34 	struct dp_mlo_ctxt *mlo_ctxt =
35 		qdf_mem_malloc(sizeof(struct dp_mlo_ctxt));
36 
37 	if (!mlo_ctxt) {
38 		dp_err("Failed to allocate DP MLO Context");
39 		return NULL;
40 	}
41 
42 	mlo_ctxt->ctrl_ctxt = ctrl_ctxt;
43 
44 	if (dp_mlo_peer_find_hash_attach_be
45 			(mlo_ctxt, DP_MAX_MLO_PEER) != QDF_STATUS_SUCCESS) {
46 		dp_err("Failed to allocate peer hash");
47 		qdf_mem_free(mlo_ctxt);
48 		return NULL;
49 	}
50 
51 	qdf_get_random_bytes(mlo_ctxt->toeplitz_hash_ipv4,
52 			     (sizeof(mlo_ctxt->toeplitz_hash_ipv4[0]) *
53 			      LRO_IPV4_SEED_ARR_SZ));
54 	qdf_get_random_bytes(mlo_ctxt->toeplitz_hash_ipv6,
55 			     (sizeof(mlo_ctxt->toeplitz_hash_ipv6[0]) *
56 			      LRO_IPV6_SEED_ARR_SZ));
57 
58 	qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock);
59 	return dp_mlo_ctx_to_cdp(mlo_ctxt);
60 }
61 
62 qdf_export_symbol(dp_mlo_ctxt_attach_wifi3);
63 
64 /*
65  * dp_mlo_ctxt_detach_wifi3 () – Detach DP MLO context
66  *
67  * @ml_ctxt: pointer to DP MLO context
68  *
69  * Return: void
70  */
71 void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt)
72 {
73 	struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
74 
75 	if (!cdp_ml_ctxt)
76 		return;
77 
78 	qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock);
79 	dp_mlo_peer_find_hash_detach_be(mlo_ctxt);
80 	qdf_mem_free(mlo_ctxt);
81 }
82 
83 qdf_export_symbol(dp_mlo_ctxt_detach_wifi3);
84 
85 /*
86  * dp_mlo_set_soc_by_chip_id() – Add DP soc to ML context soc list
87  *
88  * @ml_ctxt: DP ML context handle
89  * @soc: DP soc handle
90  * @chip_id: MLO chip id
91  *
92  * Return: void
93  */
94 void dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt *ml_ctxt,
95 			       struct dp_soc *soc,
96 			       uint8_t chip_id)
97 {
98 	qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock);
99 	ml_ctxt->ml_soc_list[chip_id] = soc;
100 	qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
101 }
102 
103 /*
104  * dp_mlo_get_soc_ref_by_chip_id() – Get DP soc from DP ML context.
105  * This API will increment a reference count for DP soc. Caller has
106  * to take care for decrementing refcount.
107  *
108  * @ml_ctxt: DP ML context handle
109  * @chip_id: MLO chip id
110  *
111  * Return: dp_soc
112  */
113 struct dp_soc*
114 dp_mlo_get_soc_ref_by_chip_id(struct dp_mlo_ctxt *ml_ctxt,
115 			      uint8_t chip_id)
116 {
117 	struct dp_soc *soc = NULL;
118 
119 	if (!ml_ctxt) {
120 		dp_warn("MLO context not created, MLO not enabled");
121 		return NULL;
122 	}
123 
124 	qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock);
125 	soc = ml_ctxt->ml_soc_list[chip_id];
126 
127 	if (!soc) {
128 		qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
129 		return NULL;
130 	}
131 
132 	qdf_atomic_inc(&soc->ref_count);
133 	qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
134 
135 	return soc;
136 }
137 
138 static QDF_STATUS dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt *mlo_ctxt,
139 					       struct dp_soc_be *be_soc)
140 {
141 	uint8_t i;
142 	struct dp_soc *partner_soc;
143 	struct dp_soc_be *be_partner_soc;
144 	uint8_t pool_id;
145 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
146 
147 	for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
148 		partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i);
149 		if (!partner_soc) {
150 			dp_err("partner_soc is NULL");
151 			continue;
152 		}
153 
154 		be_partner_soc = dp_get_be_soc_from_dp_soc(partner_soc);
155 
156 		for (pool_id = 0; pool_id < MAX_RXDESC_POOLS; pool_id++) {
157 			qdf_status =
158 				dp_hw_cookie_conversion_init
159 					(be_soc,
160 					 &be_partner_soc->rx_cc_ctx[pool_id]);
161 			if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
162 				dp_alert("MLO partner soc RX CC init failed");
163 				return qdf_status;
164 			}
165 		}
166 	}
167 
168 	return qdf_status;
169 }
170 
171 static void dp_mlo_soc_setup(struct cdp_soc_t *soc_hdl,
172 			     struct cdp_mlo_ctxt *cdp_ml_ctxt)
173 {
174 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
175 	struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
176 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
177 
178 	if (!cdp_ml_ctxt)
179 		return;
180 
181 	dp_mlo_set_soc_by_chip_id(mlo_ctxt, soc, be_soc->mlo_chip_id);
182 }
183 
184 static void dp_mlo_soc_teardown(struct cdp_soc_t *soc_hdl,
185 				struct cdp_mlo_ctxt *cdp_ml_ctxt)
186 {
187 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
188 	struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
189 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
190 
191 	if (!cdp_ml_ctxt)
192 		return;
193 
194 	dp_mlo_set_soc_by_chip_id(mlo_ctxt, NULL, be_soc->mlo_chip_id);
195 }
196 
197 static QDF_STATUS dp_mlo_add_ptnr_vdev(struct dp_vdev *vdev1,
198 				       struct dp_vdev *vdev2,
199 				       struct dp_soc *soc, uint8_t pdev_id)
200 {
201 	struct dp_soc_be *soc_be = dp_get_be_soc_from_dp_soc(soc);
202 	struct dp_vdev_be *vdev2_be = dp_get_be_vdev_from_dp_vdev(vdev2);
203 
204 	/* return when valid entry  exists */
205 	if (vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] !=
206 							CDP_INVALID_VDEV_ID)
207 		return QDF_STATUS_SUCCESS;
208 
209 	if (dp_vdev_get_ref(soc, vdev1, DP_MOD_ID_RX) !=
210 	    QDF_STATUS_SUCCESS) {
211 		qdf_info("%pK: unable to get vdev reference vdev %pK vdev_id %u",
212 			 soc, vdev1, vdev1->vdev_id);
213 		return QDF_STATUS_E_FAILURE;
214 	}
215 
216 	vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] =
217 						vdev1->vdev_id;
218 
219 	mlo_debug("Add vdev%d to vdev%d list, mlo_chip_id = %d pdev_id = %d\n",
220 		  vdev1->vdev_id, vdev2->vdev_id, soc_be->mlo_chip_id, pdev_id);
221 
222 	return QDF_STATUS_SUCCESS;
223 }
224 
225 QDF_STATUS dp_update_mlo_ptnr_list(struct cdp_soc_t *soc_hdl,
226 				   int8_t partner_vdev_ids[], uint8_t num_vdevs,
227 				   uint8_t self_vdev_id)
228 {
229 	int i, j;
230 	struct dp_soc *self_soc = cdp_soc_t_to_dp_soc(soc_hdl);
231 	struct dp_vdev *self_vdev;
232 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
233 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(self_soc);
234 	struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
235 
236 	if (!dp_mlo)
237 		return QDF_STATUS_E_FAILURE;
238 
239 	self_vdev = dp_vdev_get_ref_by_id(self_soc, self_vdev_id, DP_MOD_ID_RX);
240 	if (!self_vdev)
241 		return QDF_STATUS_E_FAILURE;
242 
243 	/* go through the input vdev id list and if there are partner vdevs,
244 	 * - then add the current vdev's id to partner vdev's list using pdev_id and
245 	 * increase the reference
246 	 * - add partner vdev to self list  and increase  the reference
247 	 */
248 	for (i = 0; i < num_vdevs; i++) {
249 		if (partner_vdev_ids[i] == CDP_INVALID_VDEV_ID)
250 			continue;
251 
252 		for (j = 0; j < WLAN_MAX_MLO_CHIPS; j++) {
253 			struct dp_soc *soc =
254 				dp_mlo_get_soc_ref_by_chip_id(dp_mlo, j);
255 			if (soc) {
256 				struct dp_vdev *vdev;
257 
258 				vdev = dp_vdev_get_ref_by_id(soc,
259 					partner_vdev_ids[i], DP_MOD_ID_RX);
260 				if (vdev) {
261 					if (vdev == self_vdev) {
262 						dp_vdev_unref_delete(soc,
263 							vdev, DP_MOD_ID_RX);
264 						/*dp_soc_unref_delete(soc); */
265 						continue;
266 					}
267 					if (qdf_is_macaddr_equal(
268 						(struct qdf_mac_addr *)self_vdev->mld_mac_addr.raw,
269 						(struct qdf_mac_addr *)vdev->mld_mac_addr.raw)) {
270 						if (dp_mlo_add_ptnr_vdev(self_vdev,
271 							vdev, self_soc,
272 							self_vdev->pdev->pdev_id) !=
273 							QDF_STATUS_SUCCESS) {
274 							dp_err("Unable to add self to partner vdev's list");
275 							dp_vdev_unref_delete(soc,
276 								vdev, DP_MOD_ID_RX);
277 							/* TODO - release soc ref here */
278 							/* dp_soc_unref_delete(soc);*/
279 							ret = QDF_STATUS_E_FAILURE;
280 							goto exit;
281 						}
282 						/* add to self list */
283 						if (dp_mlo_add_ptnr_vdev(vdev, self_vdev, soc,
284 							vdev->pdev->pdev_id) !=
285 							QDF_STATUS_SUCCESS) {
286 							dp_err("Unable to add vdev to self vdev's list");
287 							dp_vdev_unref_delete(self_soc,
288 								vdev, DP_MOD_ID_RX);
289 							/* TODO - relase soc ref here */
290 							/* dp_soc_unref_delete(soc);*/
291 							ret = QDF_STATUS_E_FAILURE;
292 							goto exit;
293 						}
294 					}
295 					dp_vdev_unref_delete(soc, vdev,
296 							     DP_MOD_ID_RX);
297 				} /* vdev */
298 				/* TODO - release soc ref here */
299 				/* dp_soc_unref_delete(soc); */
300 			} /* soc */
301 		} /* for */
302 	} /* for */
303 
304 exit:
305 	dp_vdev_unref_delete(self_soc, self_vdev, DP_MOD_ID_RX);
306 	return ret;
307 }
308 
309 void dp_clr_mlo_ptnr_list(struct dp_soc *soc, struct dp_vdev *vdev)
310 {
311 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
312 	struct dp_vdev_be *vdev_be = dp_get_be_vdev_from_dp_vdev(vdev);
313 	struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
314 	uint8_t soc_id = be_soc->mlo_chip_id;
315 	uint8_t pdev_id = vdev->pdev->pdev_id;
316 	int i, j;
317 
318 	for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
319 		for (j = 0; j < WLAN_MAX_MLO_LINKS_PER_SOC; j++) {
320 			struct dp_vdev *pr_vdev;
321 			struct dp_soc *pr_soc;
322 			struct dp_soc_be *pr_soc_be;
323 			struct dp_pdev *pr_pdev;
324 			struct dp_vdev_be *pr_vdev_be;
325 
326 			if (vdev_be->partner_vdev_list[i][j] ==
327 			    CDP_INVALID_VDEV_ID)
328 				continue;
329 
330 			pr_soc = dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
331 			if (!pr_soc)
332 				continue;
333 			pr_soc_be = dp_get_be_soc_from_dp_soc(pr_soc);
334 			pr_vdev = dp_vdev_get_ref_by_id(pr_soc,
335 						vdev_be->partner_vdev_list[i][j],
336 						DP_MOD_ID_RX);
337 			if (!pr_vdev)
338 				continue;
339 
340 			/* release ref and remove self vdev from partner list */
341 			pr_vdev_be = dp_get_be_vdev_from_dp_vdev(pr_vdev);
342 			dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX);
343 			pr_vdev_be->partner_vdev_list[soc_id][pdev_id] =
344 				CDP_INVALID_VDEV_ID;
345 
346 			/* release ref and remove partner vdev from self list */
347 			dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX);
348 			pr_pdev = pr_vdev->pdev;
349 			vdev_be->partner_vdev_list[pr_soc_be->mlo_chip_id][pr_pdev->pdev_id] =
350 				CDP_INVALID_VDEV_ID;
351 
352 			dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX);
353 		}
354 	}
355 }
356 
357 static void dp_mlo_setup_complete(struct cdp_mlo_ctxt *cdp_ml_ctxt)
358 {
359 	struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
360 	int i;
361 	struct dp_soc *soc;
362 	struct dp_soc_be *be_soc;
363 	QDF_STATUS qdf_status;
364 
365 	if (!cdp_ml_ctxt)
366 		return;
367 
368 	for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
369 		soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i);
370 
371 		if (!soc)
372 			continue;
373 		be_soc = dp_get_be_soc_from_dp_soc(soc);
374 
375 		qdf_status = dp_partner_soc_rx_hw_cc_init(mlo_ctxt, be_soc);
376 
377 		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
378 			dp_alert("MLO partner SOC Rx desc CC init failed");
379 			qdf_assert_always(0);
380 		}
381 	}
382 }
383 
384 static void dp_mlo_update_delta_tsf2(struct cdp_soc_t *soc_hdl,
385 				     uint8_t pdev_id, uint64_t delta_tsf2)
386 {
387 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
388 	struct dp_pdev *pdev;
389 	struct dp_pdev_be *be_pdev;
390 
391 	pdev = dp_get_pdev_from_soc_pdev_id_wifi3((struct dp_soc *)soc,
392 						  pdev_id);
393 	if (!pdev) {
394 		dp_err("pdev is NULL for pdev_id %u", pdev_id);
395 		return;
396 	}
397 
398 	be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
399 
400 	be_pdev->delta_tsf2 = delta_tsf2;
401 }
402 
403 static void dp_mlo_update_delta_tqm(struct cdp_soc_t *soc_hdl,
404 				    uint64_t delta_tqm)
405 {
406 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
407 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
408 
409 	be_soc->delta_tqm = delta_tqm;
410 }
411 
412 static void dp_mlo_update_mlo_ts_offset(struct cdp_soc_t *soc_hdl,
413 					uint64_t offset)
414 {
415 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
416 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
417 
418 	be_soc->mlo_tstamp_offset = offset;
419 }
420 
421 static struct cdp_mlo_ops dp_mlo_ops = {
422 	.mlo_soc_setup = dp_mlo_soc_setup,
423 	.mlo_soc_teardown = dp_mlo_soc_teardown,
424 	.update_mlo_ptnr_list = dp_update_mlo_ptnr_list,
425 	.mlo_setup_complete = dp_mlo_setup_complete,
426 	.mlo_update_delta_tsf2 = dp_mlo_update_delta_tsf2,
427 	.mlo_update_delta_tqm = dp_mlo_update_delta_tqm,
428 	.mlo_update_mlo_ts_offset = dp_mlo_update_mlo_ts_offset,
429 };
430 
431 void dp_soc_mlo_fill_params(struct dp_soc *soc,
432 			    struct cdp_soc_attach_params *params)
433 {
434 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
435 
436 	if (!params->mlo_enabled) {
437 		dp_warn("MLO not enabled on SOC");
438 		return;
439 	}
440 
441 	be_soc->mlo_chip_id = params->mlo_chip_id;
442 	be_soc->ml_ctxt = cdp_mlo_ctx_to_dp(params->ml_context);
443 	be_soc->mlo_enabled = 1;
444 	soc->cdp_soc.ops->mlo_ops = &dp_mlo_ops;
445 }
446 
447 void dp_mlo_update_link_to_pdev_map(struct dp_soc *soc, struct dp_pdev *pdev)
448 {
449 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
450 	struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
451 	struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
452 	uint8_t link_id;
453 
454 	if (!be_soc->mlo_enabled)
455 		return;
456 
457 	if (!ml_ctxt)
458 		return;
459 
460 	link_id = be_pdev->mlo_link_id;
461 
462 	if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC) {
463 		if (!ml_ctxt->link_to_pdev_map[link_id])
464 			ml_ctxt->link_to_pdev_map[link_id] = be_pdev;
465 		else
466 			dp_alert("Attempt to update existing map for link %u",
467 				 link_id);
468 	}
469 }
470 
471 void dp_mlo_update_link_to_pdev_unmap(struct dp_soc *soc, struct dp_pdev *pdev)
472 {
473 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
474 	struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
475 	struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
476 	uint8_t link_id;
477 
478 	if (!be_soc->mlo_enabled)
479 		return;
480 
481 	if (!ml_ctxt)
482 		return;
483 
484 	link_id = be_pdev->mlo_link_id;
485 
486 	if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC)
487 		ml_ctxt->link_to_pdev_map[link_id] = NULL;
488 }
489 
490 static struct dp_pdev_be *
491 dp_mlo_get_be_pdev_from_link_id(struct dp_mlo_ctxt *ml_ctxt, uint8_t link_id)
492 {
493 	if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC)
494 		return ml_ctxt->link_to_pdev_map[link_id];
495 	return NULL;
496 }
497 
498 void dp_pdev_mlo_fill_params(struct dp_pdev *pdev,
499 			     struct cdp_pdev_attach_params *params)
500 {
501 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(pdev->soc);
502 	struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
503 
504 	if (!be_soc->mlo_enabled) {
505 		dp_info("MLO not enabled on SOC");
506 		return;
507 	}
508 
509 	be_pdev->mlo_link_id = params->mlo_link_id;
510 }
511 
512 void dp_mlo_partner_chips_map(struct dp_soc *soc,
513 			      struct dp_peer *peer,
514 			      uint16_t peer_id)
515 {
516 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
517 	struct dp_mlo_ctxt *mlo_ctxt = NULL;
518 	bool is_ml_peer_id =
519 		HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id);
520 	uint8_t chip_id;
521 	struct dp_soc *temp_soc;
522 
523 	/* for non ML peer dont map on partner chips*/
524 	if (!is_ml_peer_id)
525 		return;
526 
527 	mlo_ctxt = be_soc->ml_ctxt;
528 	if (!mlo_ctxt)
529 		return;
530 
531 	qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock);
532 	for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) {
533 		temp_soc = mlo_ctxt->ml_soc_list[chip_id];
534 
535 		if (!temp_soc)
536 			continue;
537 
538 		/* skip if this is current soc */
539 		if (temp_soc == soc)
540 			continue;
541 
542 		dp_peer_find_id_to_obj_add(temp_soc, peer, peer_id);
543 	}
544 	qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock);
545 }
546 
547 qdf_export_symbol(dp_mlo_partner_chips_map);
548 
549 void dp_mlo_partner_chips_unmap(struct dp_soc *soc,
550 				uint16_t peer_id)
551 {
552 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
553 	struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
554 	bool is_ml_peer_id =
555 		HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id);
556 	uint8_t chip_id;
557 	struct dp_soc *temp_soc;
558 
559 	if (!is_ml_peer_id)
560 		return;
561 
562 	if (!mlo_ctxt)
563 		return;
564 
565 	qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock);
566 	for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) {
567 		temp_soc = mlo_ctxt->ml_soc_list[chip_id];
568 
569 		if (!temp_soc)
570 			continue;
571 
572 		/* skip if this is current soc */
573 		if (temp_soc == soc)
574 			continue;
575 
576 		dp_peer_find_id_to_obj_remove(temp_soc, peer_id);
577 	}
578 	qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock);
579 }
580 
581 qdf_export_symbol(dp_mlo_partner_chips_unmap);
582 
583 uint8_t dp_mlo_get_chip_id(struct dp_soc *soc)
584 {
585 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
586 
587 	return be_soc->mlo_chip_id;
588 }
589 
590 qdf_export_symbol(dp_mlo_get_chip_id);
591 
592 struct dp_peer *
593 dp_link_peer_hash_find_by_chip_id(struct dp_soc *soc,
594 				  uint8_t *peer_mac_addr,
595 				  int mac_addr_is_aligned,
596 				  uint8_t vdev_id,
597 				  uint8_t chip_id,
598 				  enum dp_mod_id mod_id)
599 {
600 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
601 	struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
602 	struct dp_soc *link_peer_soc = NULL;
603 	struct dp_peer *peer = NULL;
604 
605 	if (!mlo_ctxt)
606 		return NULL;
607 
608 	link_peer_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
609 
610 	if (!link_peer_soc)
611 		return NULL;
612 
613 	peer = dp_peer_find_hash_find(link_peer_soc, peer_mac_addr,
614 				      mac_addr_is_aligned, vdev_id,
615 				      mod_id);
616 	qdf_atomic_dec(&link_peer_soc->ref_count);
617 	return peer;
618 }
619 
620 qdf_export_symbol(dp_link_peer_hash_find_by_chip_id);
621 
622 void dp_mlo_get_rx_hash_key(struct dp_soc *soc,
623 			    struct cdp_lro_hash_config *lro_hash)
624 {
625 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
626 	struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
627 
628 	if (!be_soc->mlo_enabled || !ml_ctxt)
629 		return dp_get_rx_hash_key_bytes(lro_hash);
630 
631 	qdf_mem_copy(lro_hash->toeplitz_hash_ipv4, ml_ctxt->toeplitz_hash_ipv4,
632 		     (sizeof(lro_hash->toeplitz_hash_ipv4[0]) *
633 		      LRO_IPV4_SEED_ARR_SZ));
634 	qdf_mem_copy(lro_hash->toeplitz_hash_ipv6, ml_ctxt->toeplitz_hash_ipv6,
635 		     (sizeof(lro_hash->toeplitz_hash_ipv6[0]) *
636 		      LRO_IPV6_SEED_ARR_SZ));
637 }
638 
639 struct dp_soc *
640 dp_rx_replensih_soc_get(struct dp_soc *soc, uint8_t chip_id)
641 {
642 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
643 	struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
644 	struct dp_soc *replenish_soc;
645 
646 	if (!be_soc->mlo_enabled || !mlo_ctxt)
647 		return soc;
648 
649 	replenish_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
650 	if (qdf_unlikely(!replenish_soc)) {
651 		dp_alert("replenish SOC is NULL");
652 		qdf_assert_always(0);
653 	}
654 
655 	return replenish_soc;
656 }
657 
658 #ifdef WLAN_MCAST_MLO
659 void dp_mcast_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc,
660 				dp_ptnr_soc_iter_func func,
661 				void *arg)
662 {
663 	int i = 0;
664 	struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
665 
666 	for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
667 		struct dp_soc *ptnr_soc =
668 				dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
669 
670 		if (!ptnr_soc)
671 			continue;
672 		(*func)(ptnr_soc, arg);
673 	}
674 }
675 
676 qdf_export_symbol(dp_mcast_mlo_iter_ptnr_soc);
677 
678 void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc,
679 				 struct dp_vdev_be *be_vdev,
680 				 dp_ptnr_vdev_iter_func func,
681 				 void *arg,
682 				 enum dp_mod_id mod_id)
683 {
684 	int i = 0;
685 	int j = 0;
686 	struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
687 
688 	for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
689 		struct dp_soc *ptnr_soc =
690 				dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
691 
692 		if (!ptnr_soc)
693 			continue;
694 		for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
695 			struct dp_vdev *ptnr_vdev;
696 
697 			ptnr_vdev = dp_vdev_get_ref_by_id(
698 					ptnr_soc,
699 					be_vdev->partner_vdev_list[i][j],
700 					mod_id);
701 			if (!ptnr_vdev)
702 				continue;
703 			(*func)(be_vdev, ptnr_vdev, arg);
704 			dp_vdev_unref_delete(ptnr_vdev->pdev->soc,
705 					     ptnr_vdev,
706 					     mod_id);
707 		}
708 	}
709 }
710 
711 qdf_export_symbol(dp_mcast_mlo_iter_ptnr_vdev);
712 
713 struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc,
714 					      struct dp_vdev_be *be_vdev,
715 					      enum dp_mod_id mod_id)
716 {
717 	int i = 0;
718 	int j = 0;
719 	struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
720 
721 	for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
722 		struct dp_soc *ptnr_soc =
723 				dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
724 
725 		if (!ptnr_soc)
726 			continue;
727 		for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
728 			struct dp_vdev *ptnr_vdev = NULL;
729 			struct dp_vdev_be *be_ptnr_vdev = NULL;
730 
731 			ptnr_vdev = dp_vdev_get_ref_by_id(
732 					ptnr_soc,
733 					be_vdev->partner_vdev_list[i][j],
734 					mod_id);
735 			if (!ptnr_vdev)
736 				continue;
737 			be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev);
738 			if (be_ptnr_vdev->mcast_primary)
739 				return ptnr_vdev;
740 			dp_vdev_unref_delete(be_ptnr_vdev->vdev.pdev->soc,
741 					     &be_ptnr_vdev->vdev,
742 					     mod_id);
743 		}
744 	}
745 	return NULL;
746 }
747 
748 qdf_export_symbol(dp_mlo_get_mcast_primary_vdev);
749 #endif
750 
751 static inline uint64_t dp_mlo_get_mlo_ts_offset(struct dp_pdev_be *be_pdev)
752 {
753 	struct dp_soc *soc;
754 	struct dp_pdev *pdev;
755 	struct dp_soc_be *be_soc;
756 	uint32_t mlo_offset;
757 
758 	pdev = &be_pdev->pdev;
759 	soc = pdev->soc;
760 	be_soc = dp_get_be_soc_from_dp_soc(soc);
761 
762 	mlo_offset = be_soc->mlo_tstamp_offset;
763 
764 	return mlo_offset;
765 }
766 
767 int32_t dp_mlo_get_delta_tsf2_wrt_mlo_offset(struct dp_soc *soc,
768 					     uint8_t hw_link_id)
769 {
770 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
771 	struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
772 	struct dp_pdev_be *be_pdev;
773 	int32_t delta_tsf2_mlo_offset;
774 	int32_t mlo_offset, delta_tsf2;
775 
776 	if (!ml_ctxt)
777 		return 0;
778 
779 	be_pdev = dp_mlo_get_be_pdev_from_link_id(ml_ctxt, hw_link_id);
780 	if (!be_pdev)
781 		return 0;
782 
783 	mlo_offset = dp_mlo_get_mlo_ts_offset(be_pdev);
784 	delta_tsf2 = be_pdev->delta_tsf2;
785 
786 	delta_tsf2_mlo_offset = mlo_offset - delta_tsf2;
787 
788 	return delta_tsf2_mlo_offset;
789 }
790 
791 int32_t dp_mlo_get_delta_tqm_wrt_mlo_offset(struct dp_soc *soc)
792 {
793 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
794 	int32_t delta_tqm_mlo_offset;
795 	int32_t mlo_offset, delta_tqm;
796 
797 	mlo_offset = be_soc->mlo_tstamp_offset;
798 	delta_tqm = be_soc->delta_tqm;
799 
800 	delta_tqm_mlo_offset = mlo_offset - delta_tqm;
801 
802 	return delta_tqm_mlo_offset;
803 }
804