1 /*
2 * Copyright (c) 2021-2023 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_be_rx.h>
23 #include <dp_htt.h>
24 #include <dp_internal.h>
25 #include <wlan_cfg.h>
26 #include <wlan_mlo_mgr_cmn.h>
27 #include "dp_umac_reset.h"
28
29 #define dp_aggregate_vdev_stats_for_unmapped_peers(_tgtobj, _srcobj) \
30 DP_UPDATE_VDEV_STATS_FOR_UNMAPPED_PEERS(_tgtobj, _srcobj)
31
32 #ifdef DP_UMAC_HW_RESET_SUPPORT
33 /**
34 * dp_umac_reset_update_partner_map() - Update Umac reset partner map
35 * @mlo_ctx: mlo soc context
36 * @chip_id: chip id
37 * @set: flag indicating whether to set or clear the bit
38 *
39 * Return: void
40 */
41 static void dp_umac_reset_update_partner_map(struct dp_mlo_ctxt *mlo_ctx,
42 int chip_id, bool set);
43 #endif
44 /**
45 * dp_mlo_ctxt_attach_wifi3() - Attach DP MLO context
46 * @ctrl_ctxt: CDP control context
47 *
48 * Return: DP MLO context handle on success, NULL on failure
49 */
50 static struct cdp_mlo_ctxt *
dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr * ctrl_ctxt)51 dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt)
52 {
53 struct dp_mlo_ctxt *mlo_ctxt =
54 qdf_mem_malloc(sizeof(struct dp_mlo_ctxt));
55
56 if (!mlo_ctxt) {
57 dp_err("Failed to allocate DP MLO Context");
58 return NULL;
59 }
60
61 mlo_ctxt->ctrl_ctxt = ctrl_ctxt;
62
63 if (dp_mlo_peer_find_hash_attach_be
64 (mlo_ctxt, DP_MAX_MLO_PEER) != QDF_STATUS_SUCCESS) {
65 dp_err("Failed to allocate peer hash");
66 qdf_mem_free(mlo_ctxt);
67 return NULL;
68 }
69
70 qdf_get_random_bytes(mlo_ctxt->toeplitz_hash_ipv4,
71 (sizeof(mlo_ctxt->toeplitz_hash_ipv4[0]) *
72 LRO_IPV4_SEED_ARR_SZ));
73 qdf_get_random_bytes(mlo_ctxt->toeplitz_hash_ipv6,
74 (sizeof(mlo_ctxt->toeplitz_hash_ipv6[0]) *
75 LRO_IPV6_SEED_ARR_SZ));
76
77 qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock);
78 qdf_spinlock_create(&mlo_ctxt->grp_umac_reset_ctx.grp_ctx_lock);
79 dp_mlo_dev_ctxt_list_attach(mlo_ctxt);
80 return dp_mlo_ctx_to_cdp(mlo_ctxt);
81 }
82
83 /**
84 * dp_mlo_ctxt_detach_wifi3() - Detach DP MLO context
85 * @cdp_ml_ctxt: pointer to CDP DP MLO context
86 *
87 * Return: void
88 */
dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt * cdp_ml_ctxt)89 static void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt)
90 {
91 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
92
93 if (!cdp_ml_ctxt)
94 return;
95
96 qdf_spinlock_destroy(&mlo_ctxt->grp_umac_reset_ctx.grp_ctx_lock);
97 qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock);
98 dp_mlo_dev_ctxt_list_detach(mlo_ctxt);
99 dp_mlo_peer_find_hash_detach_be(mlo_ctxt);
100 qdf_mem_free(mlo_ctxt);
101 }
102
103 /**
104 * dp_mlo_set_soc_by_chip_id() - Add DP soc to ML context soc list
105 * @ml_ctxt: DP ML context handle
106 * @soc: DP soc handle
107 * @chip_id: MLO chip id
108 *
109 * Return: void
110 */
dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt * ml_ctxt,struct dp_soc * soc,uint8_t chip_id)111 static void dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt *ml_ctxt,
112 struct dp_soc *soc,
113 uint8_t chip_id)
114 {
115 qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock);
116 ml_ctxt->ml_soc_list[chip_id] = soc;
117
118 /* The same API is called during soc_attach and soc_detach
119 * soc parameter is non-null or null accordingly.
120 */
121 if (soc)
122 ml_ctxt->ml_soc_cnt++;
123 else
124 ml_ctxt->ml_soc_cnt--;
125
126 dp_umac_reset_update_partner_map(ml_ctxt, chip_id, !!soc);
127
128 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
129 }
130
131 struct dp_soc*
dp_mlo_get_soc_ref_by_chip_id(struct dp_mlo_ctxt * ml_ctxt,uint8_t chip_id)132 dp_mlo_get_soc_ref_by_chip_id(struct dp_mlo_ctxt *ml_ctxt,
133 uint8_t chip_id)
134 {
135 struct dp_soc *soc = NULL;
136
137 if (!ml_ctxt) {
138 dp_warn("MLO context not created, MLO not enabled");
139 return NULL;
140 }
141
142 qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock);
143 soc = ml_ctxt->ml_soc_list[chip_id];
144
145 if (!soc) {
146 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
147 return NULL;
148 }
149
150 qdf_atomic_inc(&soc->ref_count);
151 qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
152
153 return soc;
154 }
155
dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt * mlo_ctxt,struct dp_soc_be * be_soc)156 static QDF_STATUS dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt *mlo_ctxt,
157 struct dp_soc_be *be_soc)
158 {
159 uint8_t i;
160 struct dp_soc *partner_soc;
161 struct dp_soc_be *be_partner_soc;
162 uint8_t pool_id;
163 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
164
165 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
166 partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i);
167 if (!partner_soc) {
168 dp_err("partner_soc is NULL");
169 continue;
170 }
171
172 be_partner_soc = dp_get_be_soc_from_dp_soc(partner_soc);
173
174 for (pool_id = 0; pool_id < MAX_RXDESC_POOLS; pool_id++) {
175 qdf_status =
176 dp_hw_cookie_conversion_init
177 (be_soc,
178 &be_partner_soc->rx_cc_ctx[pool_id]);
179 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
180 dp_alert("MLO partner soc RX CC init failed");
181 return qdf_status;
182 }
183 }
184 }
185
186 return qdf_status;
187 }
188
dp_mlo_soc_drain_rx_buf(struct dp_soc * soc,void * arg,int chip_id)189 static void dp_mlo_soc_drain_rx_buf(struct dp_soc *soc, void *arg, int chip_id)
190 {
191 uint8_t i = 0;
192 uint8_t cpu = 0;
193 uint8_t rx_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0};
194 uint8_t rx_err_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0};
195 uint8_t rx_wbm_rel_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0};
196 uint8_t reo_status_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {0};
197
198 /* Save the current interrupt mask and disable the interrupts */
199 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) {
200 rx_ring_mask[i] = soc->intr_ctx[i].rx_ring_mask;
201 rx_err_ring_mask[i] = soc->intr_ctx[i].rx_err_ring_mask;
202 rx_wbm_rel_ring_mask[i] = soc->intr_ctx[i].rx_wbm_rel_ring_mask;
203 reo_status_ring_mask[i] = soc->intr_ctx[i].reo_status_ring_mask;
204
205 soc->intr_ctx[i].rx_ring_mask = 0;
206 soc->intr_ctx[i].rx_err_ring_mask = 0;
207 soc->intr_ctx[i].rx_wbm_rel_ring_mask = 0;
208 soc->intr_ctx[i].reo_status_ring_mask = 0;
209 }
210
211 /* make sure dp_service_srngs not running on any of the CPU */
212 for (cpu = 0; cpu < NR_CPUS; cpu++) {
213 while (qdf_atomic_test_bit(cpu,
214 &soc->service_rings_running))
215 ;
216 }
217
218 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) {
219 uint8_t ring = 0;
220 uint32_t num_entries = 0;
221 hal_ring_handle_t hal_ring_hdl = NULL;
222 uint8_t rx_mask = wlan_cfg_get_rx_ring_mask(
223 soc->wlan_cfg_ctx, i);
224 uint8_t rx_err_mask = wlan_cfg_get_rx_err_ring_mask(
225 soc->wlan_cfg_ctx, i);
226 uint8_t rx_wbm_rel_mask = wlan_cfg_get_rx_wbm_rel_ring_mask(
227 soc->wlan_cfg_ctx, i);
228
229 if (rx_mask) {
230 /* iterate through each reo ring and process the buf */
231 for (ring = 0; ring < soc->num_reo_dest_rings; ring++) {
232 if (!(rx_mask & (1 << ring)))
233 continue;
234
235 hal_ring_hdl =
236 soc->reo_dest_ring[ring].hal_srng;
237 num_entries = hal_srng_get_num_entries(
238 soc->hal_soc,
239 hal_ring_hdl);
240 dp_rx_process_be(&soc->intr_ctx[i],
241 hal_ring_hdl,
242 ring,
243 num_entries);
244 }
245 }
246
247 /* Process REO Exception ring */
248 if (rx_err_mask) {
249 hal_ring_hdl = soc->reo_exception_ring.hal_srng;
250 num_entries = hal_srng_get_num_entries(
251 soc->hal_soc,
252 hal_ring_hdl);
253
254 dp_rx_err_process(&soc->intr_ctx[i], soc,
255 hal_ring_hdl, num_entries);
256 }
257
258 /* Process Rx WBM release ring */
259 if (rx_wbm_rel_mask) {
260 hal_ring_hdl = soc->rx_rel_ring.hal_srng;
261 num_entries = hal_srng_get_num_entries(
262 soc->hal_soc,
263 hal_ring_hdl);
264
265 dp_rx_wbm_err_process(&soc->intr_ctx[i], soc,
266 hal_ring_hdl, num_entries);
267 }
268 }
269
270 /* restore the interrupt mask */
271 for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) {
272 soc->intr_ctx[i].rx_ring_mask = rx_ring_mask[i];
273 soc->intr_ctx[i].rx_err_ring_mask = rx_err_ring_mask[i];
274 soc->intr_ctx[i].rx_wbm_rel_ring_mask = rx_wbm_rel_ring_mask[i];
275 soc->intr_ctx[i].reo_status_ring_mask = reo_status_ring_mask[i];
276 }
277 }
278
dp_mlo_soc_setup(struct cdp_soc_t * soc_hdl,struct cdp_mlo_ctxt * cdp_ml_ctxt)279 static void dp_mlo_soc_setup(struct cdp_soc_t *soc_hdl,
280 struct cdp_mlo_ctxt *cdp_ml_ctxt)
281 {
282 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
283 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
284 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
285 uint8_t pdev_id;
286
287 if (!cdp_ml_ctxt)
288 return;
289
290 be_soc->ml_ctxt = mlo_ctxt;
291
292 for (pdev_id = 0; pdev_id < MAX_PDEV_CNT; pdev_id++) {
293 if (soc->pdev_list[pdev_id])
294 dp_mlo_update_link_to_pdev_map(soc,
295 soc->pdev_list[pdev_id]);
296 }
297
298 dp_mlo_set_soc_by_chip_id(mlo_ctxt, soc, be_soc->mlo_chip_id);
299 }
300
dp_mlo_soc_teardown(struct cdp_soc_t * soc_hdl,struct cdp_mlo_ctxt * cdp_ml_ctxt,bool is_force_down)301 static void dp_mlo_soc_teardown(struct cdp_soc_t *soc_hdl,
302 struct cdp_mlo_ctxt *cdp_ml_ctxt,
303 bool is_force_down)
304 {
305 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
306 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
307 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
308
309 if (!cdp_ml_ctxt)
310 return;
311
312 /* During the teardown drain the Rx buffers if any exist in the ring */
313 dp_mlo_iter_ptnr_soc(be_soc,
314 dp_mlo_soc_drain_rx_buf,
315 NULL);
316
317 dp_mlo_set_soc_by_chip_id(mlo_ctxt, NULL, be_soc->mlo_chip_id);
318 be_soc->ml_ctxt = NULL;
319 }
320
dp_mlo_setup_complete(struct cdp_mlo_ctxt * cdp_ml_ctxt)321 static void dp_mlo_setup_complete(struct cdp_mlo_ctxt *cdp_ml_ctxt)
322 {
323 struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
324 int i;
325 struct dp_soc *soc;
326 struct dp_soc_be *be_soc;
327 QDF_STATUS qdf_status;
328
329 if (!cdp_ml_ctxt)
330 return;
331
332 for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
333 soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i);
334
335 if (!soc)
336 continue;
337 be_soc = dp_get_be_soc_from_dp_soc(soc);
338
339 qdf_status = dp_partner_soc_rx_hw_cc_init(mlo_ctxt, be_soc);
340
341 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
342 dp_alert("MLO partner SOC Rx desc CC init failed");
343 qdf_assert_always(0);
344 }
345 }
346 }
347
dp_mlo_update_delta_tsf2(struct cdp_soc_t * soc_hdl,uint8_t pdev_id,uint64_t delta_tsf2)348 static void dp_mlo_update_delta_tsf2(struct cdp_soc_t *soc_hdl,
349 uint8_t pdev_id, uint64_t delta_tsf2)
350 {
351 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
352 struct dp_pdev *pdev;
353 struct dp_pdev_be *be_pdev;
354
355 pdev = dp_get_pdev_from_soc_pdev_id_wifi3((struct dp_soc *)soc,
356 pdev_id);
357 if (!pdev) {
358 dp_err("pdev is NULL for pdev_id %u", pdev_id);
359 return;
360 }
361
362 be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
363
364 be_pdev->delta_tsf2 = delta_tsf2;
365 }
366
dp_mlo_update_delta_tqm(struct cdp_soc_t * soc_hdl,uint64_t delta_tqm)367 static void dp_mlo_update_delta_tqm(struct cdp_soc_t *soc_hdl,
368 uint64_t delta_tqm)
369 {
370 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
371 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
372
373 be_soc->delta_tqm = delta_tqm;
374 }
375
dp_mlo_update_mlo_ts_offset(struct cdp_soc_t * soc_hdl,uint64_t offset)376 static void dp_mlo_update_mlo_ts_offset(struct cdp_soc_t *soc_hdl,
377 uint64_t offset)
378 {
379 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
380 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
381
382 be_soc->mlo_tstamp_offset = offset;
383 }
384
385 #ifdef CONFIG_MLO_SINGLE_DEV
386 /**
387 * dp_aggregate_vdev_basic_stats() - aggregate vdev basic stats
388 * @tgt_vdev_stats: target vdev buffer
389 * @src_vdev_stats: source vdev buffer
390 *
391 * return: void
392 */
393 static inline
dp_aggregate_vdev_basic_stats(struct cdp_vdev_stats * tgt_vdev_stats,struct dp_vdev_stats * src_vdev_stats)394 void dp_aggregate_vdev_basic_stats(
395 struct cdp_vdev_stats *tgt_vdev_stats,
396 struct dp_vdev_stats *src_vdev_stats)
397 {
398 DP_UPDATE_BASIC_STATS(tgt_vdev_stats, src_vdev_stats);
399 }
400
401 /**
402 * dp_aggregate_vdev_ingress_stats() - aggregate vdev ingress stats
403 * @tgt_vdev_stats: target vdev buffer
404 * @src_vdev_stats: source vdev buffer
405 * @xmit_type: xmit type of packet - MLD/Link
406 *
407 * return: void
408 */
409 static inline
dp_aggregate_vdev_ingress_stats(struct cdp_vdev_stats * tgt_vdev_stats,struct dp_vdev_stats * src_vdev_stats,enum dp_pkt_xmit_type xmit_type)410 void dp_aggregate_vdev_ingress_stats(
411 struct cdp_vdev_stats *tgt_vdev_stats,
412 struct dp_vdev_stats *src_vdev_stats,
413 enum dp_pkt_xmit_type xmit_type)
414 {
415 /* Aggregate vdev ingress stats */
416 DP_UPDATE_LINK_VDEV_INGRESS_STATS(tgt_vdev_stats, src_vdev_stats,
417 xmit_type);
418 }
419
420 /**
421 * dp_aggregate_all_vdev_stats() - aggregate vdev ingress and unmap peer stats
422 * @tgt_vdev_stats: target vdev buffer
423 * @src_vdev_stats: source vdev buffer
424 * @xmit_type: xmit type of packet - MLD/Link
425 *
426 * return: void
427 */
428 static inline
dp_aggregate_all_vdev_stats(struct cdp_vdev_stats * tgt_vdev_stats,struct dp_vdev_stats * src_vdev_stats,enum dp_pkt_xmit_type xmit_type)429 void dp_aggregate_all_vdev_stats(
430 struct cdp_vdev_stats *tgt_vdev_stats,
431 struct dp_vdev_stats *src_vdev_stats,
432 enum dp_pkt_xmit_type xmit_type)
433 {
434 dp_aggregate_vdev_ingress_stats(tgt_vdev_stats, src_vdev_stats,
435 xmit_type);
436 dp_aggregate_vdev_stats_for_unmapped_peers(tgt_vdev_stats,
437 src_vdev_stats);
438 }
439
440 /**
441 * dp_mlo_vdev_stats_aggr_bridge_vap() - aggregate bridge vdev stats
442 * @be_vdev: Dp Vdev handle
443 * @bridge_vdev: Dp vdev handle for bridge vdev
444 * @arg: buffer for target vdev stats
445 * @xmit_type: xmit type of packet - MLD/Link
446 *
447 * return: void
448 */
449 static
dp_mlo_vdev_stats_aggr_bridge_vap(struct dp_vdev_be * be_vdev,struct dp_vdev * bridge_vdev,void * arg,enum dp_pkt_xmit_type xmit_type)450 void dp_mlo_vdev_stats_aggr_bridge_vap(struct dp_vdev_be *be_vdev,
451 struct dp_vdev *bridge_vdev,
452 void *arg,
453 enum dp_pkt_xmit_type xmit_type)
454 {
455 struct cdp_vdev_stats *tgt_vdev_stats = (struct cdp_vdev_stats *)arg;
456 struct dp_vdev_be *bridge_be_vdev = NULL;
457
458 bridge_be_vdev = dp_get_be_vdev_from_dp_vdev(bridge_vdev);
459 if (!bridge_be_vdev)
460 return;
461
462 dp_aggregate_all_vdev_stats(tgt_vdev_stats, &bridge_vdev->stats,
463 xmit_type);
464 dp_aggregate_vdev_stats_for_unmapped_peers(tgt_vdev_stats,
465 (&bridge_be_vdev->mlo_stats));
466 dp_vdev_iterate_peer(bridge_vdev, dp_update_vdev_stats, tgt_vdev_stats,
467 DP_MOD_ID_GENERIC_STATS);
468 }
469
470 /**
471 * dp_mlo_vdev_stats_aggr_bridge_vap_unified() - aggregate bridge vdev stats for
472 * unified mode, all MLO and legacy packets are submitted to vdev
473 * @be_vdev: Dp Vdev handle
474 * @bridge_vdev: Dp vdev handle for bridge vdev
475 * @arg: buffer for target vdev stats
476 *
477 * return: void
478 */
479 static
dp_mlo_vdev_stats_aggr_bridge_vap_unified(struct dp_vdev_be * be_vdev,struct dp_vdev * bridge_vdev,void * arg)480 void dp_mlo_vdev_stats_aggr_bridge_vap_unified(struct dp_vdev_be *be_vdev,
481 struct dp_vdev *bridge_vdev,
482 void *arg)
483 {
484 dp_mlo_vdev_stats_aggr_bridge_vap(be_vdev, bridge_vdev, arg,
485 DP_XMIT_TOTAL);
486 }
487
488 /**
489 * dp_mlo_vdev_stats_aggr_bridge_vap_mld() - aggregate bridge vdev stats for MLD
490 * mode, all MLO packets are submitted to MLD
491 * @be_vdev: Dp Vdev handle
492 * @bridge_vdev: Dp vdev handle for bridge vdev
493 * @arg: buffer for target vdev stats
494 *
495 * return: void
496 */
497 static
dp_mlo_vdev_stats_aggr_bridge_vap_mld(struct dp_vdev_be * be_vdev,struct dp_vdev * bridge_vdev,void * arg)498 void dp_mlo_vdev_stats_aggr_bridge_vap_mld(struct dp_vdev_be *be_vdev,
499 struct dp_vdev *bridge_vdev,
500 void *arg)
501 {
502 dp_mlo_vdev_stats_aggr_bridge_vap(be_vdev, bridge_vdev, arg,
503 DP_XMIT_MLD);
504 }
505
506 /**
507 * dp_aggregate_interface_stats_based_on_peer_type() - aggregate stats at
508 * VDEV level based on peer type connected to vdev
509 * @vdev: DP VDEV handle
510 * @vdev_stats: target vdev stats pointer
511 * @peer_type: type of peer - MLO Link or Legacy peer
512 *
513 * return: void
514 */
515 static
dp_aggregate_interface_stats_based_on_peer_type(struct dp_vdev * vdev,struct cdp_vdev_stats * vdev_stats,enum dp_peer_type peer_type)516 void dp_aggregate_interface_stats_based_on_peer_type(
517 struct dp_vdev *vdev,
518 struct cdp_vdev_stats *vdev_stats,
519 enum dp_peer_type peer_type)
520 {
521 struct cdp_vdev_stats *tgt_vdev_stats = NULL;
522 struct dp_vdev_be *be_vdev = NULL;
523 struct dp_soc_be *be_soc = NULL;
524
525 if (!vdev || !vdev->pdev)
526 return;
527
528 tgt_vdev_stats = vdev_stats;
529 be_soc = dp_get_be_soc_from_dp_soc(vdev->pdev->soc);
530 be_vdev = dp_get_be_vdev_from_dp_vdev(vdev);
531 if (!be_vdev)
532 return;
533
534 if (peer_type == DP_PEER_TYPE_LEGACY) {
535 dp_aggregate_all_vdev_stats(tgt_vdev_stats,
536 &vdev->stats, DP_XMIT_LINK);
537 } else {
538 if (be_vdev->mcast_primary) {
539 dp_mlo_iter_ptnr_vdev(be_soc, be_vdev,
540 dp_mlo_vdev_stats_aggr_bridge_vap_mld,
541 (void *)vdev_stats,
542 DP_MOD_ID_GENERIC_STATS,
543 DP_BRIDGE_VDEV_ITER,
544 DP_VDEV_ITERATE_SKIP_SELF);
545 }
546 dp_aggregate_vdev_ingress_stats(tgt_vdev_stats,
547 &vdev->stats, DP_XMIT_MLD);
548 dp_aggregate_vdev_stats_for_unmapped_peers(
549 tgt_vdev_stats,
550 (&be_vdev->mlo_stats));
551 }
552
553 /* Aggregate associated peer stats */
554 dp_vdev_iterate_specific_peer_type(vdev,
555 dp_update_vdev_stats,
556 vdev_stats,
557 DP_MOD_ID_GENERIC_STATS,
558 peer_type);
559 }
560
561 /**
562 * dp_aggregate_interface_stats() - aggregate stats at VDEV level
563 * @vdev: DP VDEV handle
564 * @vdev_stats: target vdev stats pointer
565 *
566 * return: void
567 */
568 static
dp_aggregate_interface_stats(struct dp_vdev * vdev,struct cdp_vdev_stats * vdev_stats)569 void dp_aggregate_interface_stats(struct dp_vdev *vdev,
570 struct cdp_vdev_stats *vdev_stats)
571 {
572 struct dp_vdev_be *be_vdev = NULL;
573 struct dp_soc_be *be_soc = NULL;
574
575 if (!vdev || !vdev->pdev)
576 return;
577
578 be_soc = dp_get_be_soc_from_dp_soc(vdev->pdev->soc);
579 be_vdev = dp_get_be_vdev_from_dp_vdev(vdev);
580 if (!be_vdev)
581 return;
582
583 if (be_vdev->mcast_primary) {
584 dp_mlo_iter_ptnr_vdev(be_soc, be_vdev,
585 dp_mlo_vdev_stats_aggr_bridge_vap_unified,
586 (void *)vdev_stats, DP_MOD_ID_GENERIC_STATS,
587 DP_BRIDGE_VDEV_ITER,
588 DP_VDEV_ITERATE_SKIP_SELF);
589 }
590
591 dp_aggregate_vdev_stats_for_unmapped_peers(vdev_stats,
592 (&be_vdev->mlo_stats));
593 dp_aggregate_all_vdev_stats(vdev_stats, &vdev->stats,
594 DP_XMIT_TOTAL);
595
596 dp_vdev_iterate_peer(vdev, dp_update_vdev_stats, vdev_stats,
597 DP_MOD_ID_GENERIC_STATS);
598
599 dp_update_vdev_rate_stats(vdev_stats, &vdev->stats);
600 }
601
602 /**
603 * dp_mlo_aggr_ptnr_iface_stats() - aggregate mlo partner vdev stats
604 * @be_vdev: vdev handle
605 * @ptnr_vdev: partner vdev handle
606 * @arg: target buffer for aggregation
607 *
608 * return: void
609 */
610 static
dp_mlo_aggr_ptnr_iface_stats(struct dp_vdev_be * be_vdev,struct dp_vdev * ptnr_vdev,void * arg)611 void dp_mlo_aggr_ptnr_iface_stats(struct dp_vdev_be *be_vdev,
612 struct dp_vdev *ptnr_vdev,
613 void *arg)
614 {
615 struct cdp_vdev_stats *tgt_vdev_stats = (struct cdp_vdev_stats *)arg;
616
617 dp_aggregate_interface_stats(ptnr_vdev, tgt_vdev_stats);
618 }
619
620 /**
621 * dp_mlo_aggr_ptnr_iface_stats_mlo_links() - aggregate mlo partner vdev stats
622 * based on peer type
623 * @be_vdev: vdev handle
624 * @ptnr_vdev: partner vdev handle
625 * @arg: target buffer for aggregation
626 *
627 * return: void
628 */
629 static
dp_mlo_aggr_ptnr_iface_stats_mlo_links(struct dp_vdev_be * be_vdev,struct dp_vdev * ptnr_vdev,void * arg)630 void dp_mlo_aggr_ptnr_iface_stats_mlo_links(
631 struct dp_vdev_be *be_vdev,
632 struct dp_vdev *ptnr_vdev,
633 void *arg)
634 {
635 struct cdp_vdev_stats *tgt_vdev_stats = (struct cdp_vdev_stats *)arg;
636
637 dp_aggregate_interface_stats_based_on_peer_type(ptnr_vdev,
638 tgt_vdev_stats,
639 DP_PEER_TYPE_MLO_LINK);
640 }
641
642 /**
643 * dp_aggregate_sta_interface_stats() - for sta mode aggregate vdev stats from
644 * all link peers
645 * @soc: soc handle
646 * @vdev: vdev handle
647 * @buf: target buffer for aggregation
648 *
649 * return: QDF_STATUS
650 */
651 static QDF_STATUS
dp_aggregate_sta_interface_stats(struct dp_soc * soc,struct dp_vdev * vdev,void * buf)652 dp_aggregate_sta_interface_stats(struct dp_soc *soc,
653 struct dp_vdev *vdev,
654 void *buf)
655 {
656 struct dp_peer *vap_bss_peer = NULL;
657 struct dp_peer *mld_peer = NULL;
658 struct dp_peer *link_peer = NULL;
659 struct dp_mld_link_peers link_peers_info;
660 uint8_t i = 0;
661 QDF_STATUS ret = QDF_STATUS_SUCCESS;
662
663 vap_bss_peer = dp_vdev_bss_peer_ref_n_get(soc, vdev,
664 DP_MOD_ID_GENERIC_STATS);
665 if (!vap_bss_peer)
666 return QDF_STATUS_E_FAILURE;
667
668 mld_peer = DP_GET_MLD_PEER_FROM_PEER(vap_bss_peer);
669
670 if (!mld_peer) {
671 dp_peer_unref_delete(vap_bss_peer, DP_MOD_ID_GENERIC_STATS);
672 return QDF_STATUS_E_FAILURE;
673 }
674
675 dp_get_link_peers_ref_from_mld_peer(soc, mld_peer, &link_peers_info,
676 DP_MOD_ID_GENERIC_STATS);
677
678 for (i = 0; i < link_peers_info.num_links; i++) {
679 link_peer = link_peers_info.link_peers[i];
680 dp_update_vdev_stats(soc, link_peer, buf);
681 dp_aggregate_vdev_ingress_stats((struct cdp_vdev_stats *)buf,
682 &link_peer->vdev->stats,
683 DP_XMIT_TOTAL);
684 dp_aggregate_vdev_basic_stats(
685 (struct cdp_vdev_stats *)buf,
686 &link_peer->vdev->stats);
687 }
688
689 dp_release_link_peers_ref(&link_peers_info, DP_MOD_ID_GENERIC_STATS);
690 dp_peer_unref_delete(vap_bss_peer, DP_MOD_ID_GENERIC_STATS);
691 return ret;
692 }
693
dp_mlo_get_mld_vdev_stats(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,void * buf,bool link_vdev_only)694 static QDF_STATUS dp_mlo_get_mld_vdev_stats(struct cdp_soc_t *soc_hdl,
695 uint8_t vdev_id, void *buf,
696 bool link_vdev_only)
697 {
698 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
699 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
700 struct dp_vdev *vdev = dp_vdev_get_ref_by_id(soc, vdev_id,
701 DP_MOD_ID_GENERIC_STATS);
702 struct dp_vdev_be *vdev_be = NULL;
703 QDF_STATUS ret = QDF_STATUS_SUCCESS;
704
705 if (!vdev)
706 return QDF_STATUS_E_FAILURE;
707
708 vdev_be = dp_get_be_vdev_from_dp_vdev(vdev);
709 if (!vdev_be || !vdev_be->mlo_dev_ctxt) {
710 dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_GENERIC_STATS);
711 return QDF_STATUS_E_FAILURE;
712 }
713
714 if (vdev->opmode == wlan_op_mode_sta) {
715 ret = dp_aggregate_sta_interface_stats(soc, vdev, buf);
716 goto complete;
717 }
718
719 if (DP_MLD_MODE_HYBRID_NONBOND == soc->mld_mode_ap &&
720 vdev->opmode == wlan_op_mode_ap) {
721 dp_aggregate_interface_stats_based_on_peer_type(
722 vdev, buf,
723 DP_PEER_TYPE_MLO_LINK);
724 if (link_vdev_only)
725 goto complete;
726
727 /* Aggregate stats from partner vdevs */
728 dp_mlo_iter_ptnr_vdev(be_soc, vdev_be,
729 dp_mlo_aggr_ptnr_iface_stats_mlo_links,
730 buf,
731 DP_MOD_ID_GENERIC_STATS,
732 DP_LINK_VDEV_ITER,
733 DP_VDEV_ITERATE_SKIP_SELF);
734
735 /* Aggregate vdev stats from MLO ctx for detached MLO Links */
736 dp_update_mlo_link_vdev_ctxt_stats(buf,
737 &vdev_be->mlo_dev_ctxt->stats,
738 DP_XMIT_MLD);
739 } else {
740 dp_aggregate_interface_stats(vdev, buf);
741
742 if (link_vdev_only)
743 goto complete;
744
745 /* Aggregate stats from partner vdevs */
746 dp_mlo_iter_ptnr_vdev(be_soc, vdev_be,
747 dp_mlo_aggr_ptnr_iface_stats, buf,
748 DP_MOD_ID_GENERIC_STATS,
749 DP_LINK_VDEV_ITER,
750 DP_VDEV_ITERATE_SKIP_SELF);
751
752 /* Aggregate vdev stats from MLO ctx for detached MLO Links */
753 dp_update_mlo_link_vdev_ctxt_stats(buf,
754 &vdev_be->mlo_dev_ctxt->stats,
755 DP_XMIT_TOTAL);
756 }
757
758 complete:
759 dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_GENERIC_STATS);
760 return ret;
761 }
762
763 QDF_STATUS
dp_get_interface_stats_be(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,void * buf,bool is_aggregate)764 dp_get_interface_stats_be(struct cdp_soc_t *soc_hdl,
765 uint8_t vdev_id,
766 void *buf,
767 bool is_aggregate)
768 {
769 struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
770 struct dp_vdev *vdev = dp_vdev_get_ref_by_id(soc, vdev_id,
771 DP_MOD_ID_GENERIC_STATS);
772 if (!vdev)
773 return QDF_STATUS_E_FAILURE;
774
775 if (DP_MLD_MODE_HYBRID_NONBOND == soc->mld_mode_ap &&
776 vdev->opmode == wlan_op_mode_ap) {
777 dp_aggregate_interface_stats_based_on_peer_type(
778 vdev, buf,
779 DP_PEER_TYPE_LEGACY);
780 } else {
781 dp_aggregate_interface_stats(vdev, buf);
782 }
783
784 dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_GENERIC_STATS);
785
786 return QDF_STATUS_SUCCESS;
787 }
788 #endif
789
790 static struct cdp_mlo_ops dp_mlo_ops = {
791 .mlo_soc_setup = dp_mlo_soc_setup,
792 .mlo_soc_teardown = dp_mlo_soc_teardown,
793 .mlo_setup_complete = dp_mlo_setup_complete,
794 .mlo_update_delta_tsf2 = dp_mlo_update_delta_tsf2,
795 .mlo_update_delta_tqm = dp_mlo_update_delta_tqm,
796 .mlo_update_mlo_ts_offset = dp_mlo_update_mlo_ts_offset,
797 .mlo_ctxt_attach = dp_mlo_ctxt_attach_wifi3,
798 .mlo_ctxt_detach = dp_mlo_ctxt_detach_wifi3,
799 #ifdef CONFIG_MLO_SINGLE_DEV
800 .mlo_get_mld_vdev_stats = dp_mlo_get_mld_vdev_stats,
801 #endif
802 };
803
dp_soc_mlo_fill_params(struct dp_soc * soc,struct cdp_soc_attach_params * params)804 void dp_soc_mlo_fill_params(struct dp_soc *soc,
805 struct cdp_soc_attach_params *params)
806 {
807 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
808
809 if (!params->mlo_enabled) {
810 dp_warn("MLO not enabled on SOC");
811 return;
812 }
813
814 be_soc->mlo_chip_id = params->mlo_chip_id;
815 be_soc->ml_ctxt = cdp_mlo_ctx_to_dp(params->ml_context);
816 be_soc->mlo_enabled = 1;
817 soc->cdp_soc.ops->mlo_ops = &dp_mlo_ops;
818 }
819
dp_mlo_update_link_to_pdev_map(struct dp_soc * soc,struct dp_pdev * pdev)820 void dp_mlo_update_link_to_pdev_map(struct dp_soc *soc, struct dp_pdev *pdev)
821 {
822 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
823 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
824 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
825 uint8_t link_id;
826
827 if (!be_soc->mlo_enabled)
828 return;
829
830 if (!ml_ctxt)
831 return;
832
833 link_id = be_pdev->mlo_link_id;
834
835 if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC) {
836 if (!ml_ctxt->link_to_pdev_map[link_id])
837 ml_ctxt->link_to_pdev_map[link_id] = be_pdev;
838 else
839 dp_alert("Attempt to update existing map for link %u",
840 link_id);
841 }
842 }
843
dp_mlo_update_link_to_pdev_unmap(struct dp_soc * soc,struct dp_pdev * pdev)844 void dp_mlo_update_link_to_pdev_unmap(struct dp_soc *soc, struct dp_pdev *pdev)
845 {
846 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
847 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
848 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
849 uint8_t link_id;
850
851 if (!be_soc->mlo_enabled)
852 return;
853
854 if (!ml_ctxt)
855 return;
856
857 link_id = be_pdev->mlo_link_id;
858
859 if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC)
860 ml_ctxt->link_to_pdev_map[link_id] = NULL;
861 }
862
863 static struct dp_pdev_be *
dp_mlo_get_be_pdev_from_link_id(struct dp_mlo_ctxt * ml_ctxt,uint8_t link_id)864 dp_mlo_get_be_pdev_from_link_id(struct dp_mlo_ctxt *ml_ctxt, uint8_t link_id)
865 {
866 if (link_id < WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC)
867 return ml_ctxt->link_to_pdev_map[link_id];
868 return NULL;
869 }
870
dp_pdev_mlo_fill_params(struct dp_pdev * pdev,struct cdp_pdev_attach_params * params)871 void dp_pdev_mlo_fill_params(struct dp_pdev *pdev,
872 struct cdp_pdev_attach_params *params)
873 {
874 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(pdev->soc);
875 struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
876
877 if (!be_soc->mlo_enabled) {
878 dp_info("MLO not enabled on SOC");
879 return;
880 }
881
882 be_pdev->mlo_link_id = params->mlo_link_id;
883 }
884
dp_mlo_partner_chips_map(struct dp_soc * soc,struct dp_peer * peer,uint16_t peer_id)885 void dp_mlo_partner_chips_map(struct dp_soc *soc,
886 struct dp_peer *peer,
887 uint16_t peer_id)
888 {
889 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
890 struct dp_mlo_ctxt *mlo_ctxt = NULL;
891 bool is_ml_peer_id =
892 HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id);
893 uint8_t chip_id;
894 struct dp_soc *temp_soc;
895
896 /* for non ML peer dont map on partner chips*/
897 if (!is_ml_peer_id)
898 return;
899
900 mlo_ctxt = be_soc->ml_ctxt;
901 if (!mlo_ctxt)
902 return;
903
904 qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock);
905 for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) {
906 temp_soc = mlo_ctxt->ml_soc_list[chip_id];
907
908 if (!temp_soc)
909 continue;
910
911 /* skip if this is current soc */
912 if (temp_soc == soc)
913 continue;
914
915 dp_peer_find_id_to_obj_add(temp_soc, peer, peer_id);
916 }
917 qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock);
918 }
919
920 qdf_export_symbol(dp_mlo_partner_chips_map);
921
dp_mlo_partner_chips_unmap(struct dp_soc * soc,uint16_t peer_id)922 void dp_mlo_partner_chips_unmap(struct dp_soc *soc,
923 uint16_t peer_id)
924 {
925 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
926 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
927 bool is_ml_peer_id =
928 HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id);
929 uint8_t chip_id;
930 struct dp_soc *temp_soc;
931
932 if (!is_ml_peer_id)
933 return;
934
935 if (!mlo_ctxt)
936 return;
937
938 qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock);
939 for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) {
940 temp_soc = mlo_ctxt->ml_soc_list[chip_id];
941
942 if (!temp_soc)
943 continue;
944
945 /* skip if this is current soc */
946 if (temp_soc == soc)
947 continue;
948
949 dp_peer_find_id_to_obj_remove(temp_soc, peer_id);
950 }
951 qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock);
952 }
953
954 qdf_export_symbol(dp_mlo_partner_chips_unmap);
955
dp_mlo_get_chip_id(struct dp_soc * soc)956 uint8_t dp_mlo_get_chip_id(struct dp_soc *soc)
957 {
958 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
959
960 return be_soc->mlo_chip_id;
961 }
962
963 qdf_export_symbol(dp_mlo_get_chip_id);
964
965 struct dp_peer *
dp_mlo_link_peer_hash_find_by_chip_id(struct dp_soc * soc,uint8_t * peer_mac_addr,int mac_addr_is_aligned,uint8_t vdev_id,uint8_t chip_id,enum dp_mod_id mod_id)966 dp_mlo_link_peer_hash_find_by_chip_id(struct dp_soc *soc,
967 uint8_t *peer_mac_addr,
968 int mac_addr_is_aligned,
969 uint8_t vdev_id,
970 uint8_t chip_id,
971 enum dp_mod_id mod_id)
972 {
973 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
974 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
975 struct dp_soc *link_peer_soc = NULL;
976 struct dp_peer *peer = NULL;
977
978 if (!mlo_ctxt)
979 return NULL;
980
981 link_peer_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
982
983 if (!link_peer_soc)
984 return NULL;
985
986 peer = dp_peer_find_hash_find(link_peer_soc, peer_mac_addr,
987 mac_addr_is_aligned, vdev_id,
988 mod_id);
989 qdf_atomic_dec(&link_peer_soc->ref_count);
990 return peer;
991 }
992
993 qdf_export_symbol(dp_mlo_link_peer_hash_find_by_chip_id);
994
dp_mlo_get_rx_hash_key(struct dp_soc * soc,struct cdp_lro_hash_config * lro_hash)995 void dp_mlo_get_rx_hash_key(struct dp_soc *soc,
996 struct cdp_lro_hash_config *lro_hash)
997 {
998 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
999 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
1000
1001 if (!be_soc->mlo_enabled || !ml_ctxt)
1002 return dp_get_rx_hash_key_bytes(lro_hash);
1003
1004 qdf_mem_copy(lro_hash->toeplitz_hash_ipv4, ml_ctxt->toeplitz_hash_ipv4,
1005 (sizeof(lro_hash->toeplitz_hash_ipv4[0]) *
1006 LRO_IPV4_SEED_ARR_SZ));
1007 qdf_mem_copy(lro_hash->toeplitz_hash_ipv6, ml_ctxt->toeplitz_hash_ipv6,
1008 (sizeof(lro_hash->toeplitz_hash_ipv6[0]) *
1009 LRO_IPV6_SEED_ARR_SZ));
1010 }
1011
1012 struct dp_soc *
dp_rx_replenish_soc_get(struct dp_soc * soc,uint8_t chip_id)1013 dp_rx_replenish_soc_get(struct dp_soc *soc, uint8_t chip_id)
1014 {
1015 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1016 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
1017 struct dp_soc *replenish_soc;
1018
1019 if (!be_soc->mlo_enabled || !mlo_ctxt)
1020 return soc;
1021
1022 if (be_soc->mlo_chip_id == chip_id)
1023 return soc;
1024
1025 replenish_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
1026 if (qdf_unlikely(!replenish_soc)) {
1027 dp_alert("replenish SOC is NULL");
1028 qdf_assert_always(0);
1029 }
1030
1031 return replenish_soc;
1032 }
1033
dp_soc_get_num_soc_be(struct dp_soc * soc)1034 uint8_t dp_soc_get_num_soc_be(struct dp_soc *soc)
1035 {
1036 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1037 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
1038
1039 if (!be_soc->mlo_enabled || !mlo_ctxt)
1040 return 1;
1041
1042 return mlo_ctxt->ml_soc_cnt;
1043 }
1044
1045 struct dp_soc *
dp_soc_get_by_idle_bm_id(struct dp_soc * soc,uint8_t idle_bm_id)1046 dp_soc_get_by_idle_bm_id(struct dp_soc *soc, uint8_t idle_bm_id)
1047 {
1048 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1049 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
1050 struct dp_soc *partner_soc = NULL;
1051 uint8_t chip_id;
1052
1053 if (!be_soc->mlo_enabled || !mlo_ctxt)
1054 return soc;
1055
1056 for (chip_id = 0; chip_id < WLAN_MAX_MLO_CHIPS; chip_id++) {
1057 partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
1058
1059 if (!partner_soc)
1060 continue;
1061
1062 if (partner_soc->idle_link_bm_id == idle_bm_id)
1063 return partner_soc;
1064 }
1065
1066 return NULL;
1067 }
1068
1069 #ifdef WLAN_MLO_MULTI_CHIP
dp_print_mlo_partner_list(struct dp_vdev_be * be_vdev,struct dp_vdev * partner_vdev,void * arg)1070 static void dp_print_mlo_partner_list(struct dp_vdev_be *be_vdev,
1071 struct dp_vdev *partner_vdev,
1072 void *arg)
1073 {
1074 struct dp_vdev_be *partner_vdev_be = NULL;
1075 struct dp_soc_be *partner_soc_be = NULL;
1076
1077 partner_vdev_be = dp_get_be_vdev_from_dp_vdev(partner_vdev);
1078 partner_soc_be = dp_get_be_soc_from_dp_soc(partner_vdev->pdev->soc);
1079
1080 DP_PRINT_STATS("is_bridge_vap = %s, mcast_primary = %s, vdev_id = %d, pdev_id = %d, chip_id = %d",
1081 partner_vdev->is_bridge_vdev ? "true" : "false",
1082 partner_vdev_be->mcast_primary ? "true" : "false",
1083 partner_vdev->vdev_id,
1084 partner_vdev->pdev->pdev_id,
1085 partner_soc_be->mlo_chip_id);
1086 }
1087
dp_mlo_iter_ptnr_vdev(struct dp_soc_be * be_soc,struct dp_vdev_be * be_vdev,dp_ptnr_vdev_iter_func func,void * arg,enum dp_mod_id mod_id,uint8_t type,bool include_self_vdev)1088 void dp_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc,
1089 struct dp_vdev_be *be_vdev,
1090 dp_ptnr_vdev_iter_func func,
1091 void *arg,
1092 enum dp_mod_id mod_id,
1093 uint8_t type,
1094 bool include_self_vdev)
1095 {
1096 int i = 0;
1097 int j = 0;
1098 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
1099 struct dp_vdev *self_vdev = &be_vdev->vdev;
1100
1101 if (type < DP_LINK_VDEV_ITER || type > DP_ALL_VDEV_ITER) {
1102 dp_err("invalid iterate type");
1103 return;
1104 }
1105
1106 if (!be_vdev->mlo_dev_ctxt) {
1107 if (!include_self_vdev)
1108 return;
1109 (*func)(be_vdev, self_vdev, arg);
1110 }
1111
1112 for (i = 0; (i < WLAN_MAX_MLO_CHIPS) &&
1113 IS_LINK_VDEV_ITER_REQUIRED(type); i++) {
1114 struct dp_soc *ptnr_soc =
1115 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
1116
1117 if (!ptnr_soc)
1118 continue;
1119 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
1120 struct dp_vdev *ptnr_vdev;
1121
1122 ptnr_vdev = dp_vdev_get_ref_by_id(
1123 ptnr_soc,
1124 be_vdev->mlo_dev_ctxt->vdev_list[i][j],
1125 mod_id);
1126 if (!ptnr_vdev)
1127 continue;
1128
1129 if ((ptnr_vdev == self_vdev) && (!include_self_vdev)) {
1130 dp_vdev_unref_delete(ptnr_vdev->pdev->soc,
1131 ptnr_vdev,
1132 mod_id);
1133 continue;
1134 }
1135
1136 (*func)(be_vdev, ptnr_vdev, arg);
1137 dp_vdev_unref_delete(ptnr_vdev->pdev->soc,
1138 ptnr_vdev,
1139 mod_id);
1140 }
1141 }
1142
1143 for (i = 0; (i < WLAN_MAX_MLO_CHIPS) &&
1144 IS_BRIDGE_VDEV_ITER_REQUIRED(type); i++) {
1145 struct dp_soc *ptnr_soc =
1146 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
1147
1148 if (!ptnr_soc)
1149 continue;
1150 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
1151 struct dp_vdev *bridge_vdev;
1152
1153 bridge_vdev = dp_vdev_get_ref_by_id(
1154 ptnr_soc,
1155 be_vdev->mlo_dev_ctxt->bridge_vdev[i][j],
1156 mod_id);
1157
1158 if (!bridge_vdev)
1159 continue;
1160
1161 if ((bridge_vdev == self_vdev) &&
1162 (!include_self_vdev)) {
1163 dp_vdev_unref_delete(
1164 bridge_vdev->pdev->soc,
1165 bridge_vdev,
1166 mod_id);
1167 continue;
1168 }
1169
1170 (*func)(be_vdev, bridge_vdev, arg);
1171 dp_vdev_unref_delete(bridge_vdev->pdev->soc,
1172 bridge_vdev,
1173 mod_id);
1174 }
1175 }
1176 }
1177
1178 qdf_export_symbol(dp_mlo_iter_ptnr_vdev);
1179
dp_mlo_debug_print_ptnr_info(struct dp_vdev * vdev)1180 void dp_mlo_debug_print_ptnr_info(struct dp_vdev *vdev)
1181 {
1182 struct dp_vdev_be *be_vdev = NULL;
1183 struct dp_soc_be *be_soc = NULL;
1184
1185 be_soc = dp_get_be_soc_from_dp_soc(vdev->pdev->soc);
1186 be_vdev = dp_get_be_vdev_from_dp_vdev(vdev);
1187
1188 DP_PRINT_STATS("self vdev is_bridge_vap = %s, mcast_primary = %s, vdev = %d, pdev_id = %d, chip_id = %d",
1189 vdev->is_bridge_vdev ? "true" : "false",
1190 be_vdev->mcast_primary ? "true" : "false",
1191 vdev->vdev_id,
1192 vdev->pdev->pdev_id,
1193 dp_mlo_get_chip_id(vdev->pdev->soc));
1194
1195 dp_mlo_iter_ptnr_vdev(be_soc, be_vdev,
1196 dp_print_mlo_partner_list,
1197 NULL, DP_MOD_ID_GENERIC_STATS,
1198 DP_ALL_VDEV_ITER,
1199 DP_VDEV_ITERATE_SKIP_SELF);
1200 }
1201 #endif
1202
1203 #ifdef WLAN_MCAST_MLO
dp_mlo_get_mcast_primary_vdev(struct dp_soc_be * be_soc,struct dp_vdev_be * be_vdev,enum dp_mod_id mod_id)1204 struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc,
1205 struct dp_vdev_be *be_vdev,
1206 enum dp_mod_id mod_id)
1207 {
1208 int i = 0;
1209 int j = 0;
1210 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
1211 struct dp_vdev *vdev = (struct dp_vdev *)be_vdev;
1212
1213 if (!be_vdev->mlo_dev_ctxt) {
1214 return NULL;
1215 }
1216
1217 if (be_vdev->mcast_primary) {
1218 if (dp_vdev_get_ref((struct dp_soc *)be_soc, vdev, mod_id) !=
1219 QDF_STATUS_SUCCESS)
1220 return NULL;
1221
1222 return vdev;
1223 }
1224
1225 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
1226 struct dp_soc *ptnr_soc =
1227 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
1228
1229 if (!ptnr_soc)
1230 continue;
1231 for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
1232 struct dp_vdev *ptnr_vdev = NULL;
1233 struct dp_vdev_be *be_ptnr_vdev = NULL;
1234
1235 ptnr_vdev = dp_vdev_get_ref_by_id(
1236 ptnr_soc,
1237 be_vdev->mlo_dev_ctxt->vdev_list[i][j],
1238 mod_id);
1239 if (!ptnr_vdev)
1240 continue;
1241 be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev);
1242 if (be_ptnr_vdev->mcast_primary)
1243 return ptnr_vdev;
1244 dp_vdev_unref_delete(be_ptnr_vdev->vdev.pdev->soc,
1245 &be_ptnr_vdev->vdev,
1246 mod_id);
1247 }
1248 }
1249 return NULL;
1250 }
1251
1252 qdf_export_symbol(dp_mlo_get_mcast_primary_vdev);
1253 #endif
1254
1255 /**
1256 * dp_mlo_iter_ptnr_soc() - iterate through mlo soc list and call the callback
1257 * @be_soc: dp_soc_be pointer
1258 * @func: Function to be called for each soc
1259 * @arg: context to be passed to the callback
1260 *
1261 * Return: true if mlo is enabled, false if mlo is disabled
1262 */
dp_mlo_iter_ptnr_soc(struct dp_soc_be * be_soc,dp_ptnr_soc_iter_func func,void * arg)1263 bool dp_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, dp_ptnr_soc_iter_func func,
1264 void *arg)
1265 {
1266 int i = 0;
1267 struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
1268
1269 if (!be_soc->mlo_enabled || !be_soc->ml_ctxt)
1270 return false;
1271
1272 for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
1273 struct dp_soc *ptnr_soc =
1274 dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
1275
1276 if (!ptnr_soc)
1277 continue;
1278 (*func)(ptnr_soc, arg, i);
1279 }
1280
1281 return true;
1282 }
1283
1284 qdf_export_symbol(dp_mlo_iter_ptnr_soc);
1285
dp_mlo_get_mlo_ts_offset(struct dp_pdev_be * be_pdev)1286 static inline uint64_t dp_mlo_get_mlo_ts_offset(struct dp_pdev_be *be_pdev)
1287 {
1288 struct dp_soc *soc;
1289 struct dp_pdev *pdev;
1290 struct dp_soc_be *be_soc;
1291 uint32_t mlo_offset;
1292
1293 pdev = &be_pdev->pdev;
1294 soc = pdev->soc;
1295 be_soc = dp_get_be_soc_from_dp_soc(soc);
1296
1297 mlo_offset = be_soc->mlo_tstamp_offset;
1298
1299 return mlo_offset;
1300 }
1301
dp_mlo_get_delta_tsf2_wrt_mlo_offset(struct dp_soc * soc,uint8_t hw_link_id)1302 int32_t dp_mlo_get_delta_tsf2_wrt_mlo_offset(struct dp_soc *soc,
1303 uint8_t hw_link_id)
1304 {
1305 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1306 struct dp_mlo_ctxt *ml_ctxt = be_soc->ml_ctxt;
1307 struct dp_pdev_be *be_pdev;
1308 int32_t delta_tsf2_mlo_offset;
1309 int32_t mlo_offset, delta_tsf2;
1310
1311 if (!ml_ctxt)
1312 return 0;
1313
1314 be_pdev = dp_mlo_get_be_pdev_from_link_id(ml_ctxt, hw_link_id);
1315 if (!be_pdev)
1316 return 0;
1317
1318 mlo_offset = dp_mlo_get_mlo_ts_offset(be_pdev);
1319 delta_tsf2 = be_pdev->delta_tsf2;
1320
1321 delta_tsf2_mlo_offset = mlo_offset - delta_tsf2;
1322
1323 return delta_tsf2_mlo_offset;
1324 }
1325
dp_mlo_get_delta_tqm_wrt_mlo_offset(struct dp_soc * soc)1326 int32_t dp_mlo_get_delta_tqm_wrt_mlo_offset(struct dp_soc *soc)
1327 {
1328 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1329 int32_t delta_tqm_mlo_offset;
1330 int32_t mlo_offset, delta_tqm;
1331
1332 mlo_offset = be_soc->mlo_tstamp_offset;
1333 delta_tqm = be_soc->delta_tqm;
1334
1335 delta_tqm_mlo_offset = mlo_offset - delta_tqm;
1336
1337 return delta_tqm_mlo_offset;
1338 }
1339
1340 #ifdef DP_UMAC_HW_RESET_SUPPORT
1341 /**
1342 * dp_umac_reset_update_partner_map() - Update Umac reset partner map
1343 * @mlo_ctx: DP ML context handle
1344 * @chip_id: chip id
1345 * @set: flag indicating whether to set or clear the bit
1346 *
1347 * Return: void
1348 */
dp_umac_reset_update_partner_map(struct dp_mlo_ctxt * mlo_ctx,int chip_id,bool set)1349 static void dp_umac_reset_update_partner_map(struct dp_mlo_ctxt *mlo_ctx,
1350 int chip_id, bool set)
1351 {
1352 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx =
1353 &mlo_ctx->grp_umac_reset_ctx;
1354
1355 if (set)
1356 qdf_atomic_set_bit(chip_id, &grp_umac_reset_ctx->partner_map);
1357 else
1358 qdf_atomic_clear_bit(chip_id, &grp_umac_reset_ctx->partner_map);
1359 }
1360
dp_umac_reset_notify_asserted_soc(struct dp_soc * soc)1361 QDF_STATUS dp_umac_reset_notify_asserted_soc(struct dp_soc *soc)
1362 {
1363 struct dp_mlo_ctxt *mlo_ctx;
1364 struct dp_soc_be *be_soc;
1365
1366 be_soc = dp_get_be_soc_from_dp_soc(soc);
1367 if (!be_soc) {
1368 dp_umac_reset_err("null be_soc");
1369 return QDF_STATUS_E_NULL_VALUE;
1370 }
1371
1372 mlo_ctx = be_soc->ml_ctxt;
1373 if (!mlo_ctx) {
1374 /* This API can be called for non-MLO SOC as well. Hence, return
1375 * the status as success when mlo_ctx is NULL.
1376 */
1377 return QDF_STATUS_SUCCESS;
1378 }
1379
1380 dp_umac_reset_update_partner_map(mlo_ctx, be_soc->mlo_chip_id, false);
1381
1382 return QDF_STATUS_SUCCESS;
1383 }
1384
1385 /**
1386 * dp_umac_reset_complete_umac_recovery() - Complete Umac reset session
1387 * @soc: dp soc handle
1388 *
1389 * Return: void
1390 */
dp_umac_reset_complete_umac_recovery(struct dp_soc * soc)1391 void dp_umac_reset_complete_umac_recovery(struct dp_soc *soc)
1392 {
1393 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1394 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1395 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1396
1397 if (!mlo_ctx) {
1398 dp_umac_reset_alert("Umac reset was handled on soc %pK", soc);
1399 return;
1400 }
1401
1402 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1403 qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1404
1405 grp_umac_reset_ctx->umac_reset_in_progress = false;
1406 grp_umac_reset_ctx->is_target_recovery = false;
1407 grp_umac_reset_ctx->response_map = 0;
1408 grp_umac_reset_ctx->request_map = 0;
1409 grp_umac_reset_ctx->initiator_chip_id = 0;
1410
1411 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1412
1413 dp_umac_reset_alert("Umac reset was handled on mlo group ctxt %pK",
1414 mlo_ctx);
1415 }
1416
1417 /**
1418 * dp_umac_reset_initiate_umac_recovery() - Initiate Umac reset session
1419 * @soc: dp soc handle
1420 * @umac_reset_ctx: Umac reset context
1421 * @rx_event: Rx event received
1422 * @is_target_recovery: Flag to indicate if it is triggered for target recovery
1423 *
1424 * Return: status
1425 */
dp_umac_reset_initiate_umac_recovery(struct dp_soc * soc,struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_rx_event rx_event,bool is_target_recovery)1426 QDF_STATUS dp_umac_reset_initiate_umac_recovery(struct dp_soc *soc,
1427 struct dp_soc_umac_reset_ctx *umac_reset_ctx,
1428 enum umac_reset_rx_event rx_event,
1429 bool is_target_recovery)
1430 {
1431 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1432 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1433 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1434 QDF_STATUS status = QDF_STATUS_SUCCESS;
1435
1436 if (!mlo_ctx)
1437 return dp_umac_reset_validate_n_update_state_machine_on_rx(
1438 umac_reset_ctx, rx_event,
1439 UMAC_RESET_STATE_WAIT_FOR_TRIGGER,
1440 UMAC_RESET_STATE_DO_TRIGGER_RECEIVED);
1441
1442 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1443 qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1444
1445 if (grp_umac_reset_ctx->umac_reset_in_progress) {
1446 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1447 return QDF_STATUS_E_INVAL;
1448 }
1449
1450 status = dp_umac_reset_validate_n_update_state_machine_on_rx(
1451 umac_reset_ctx, rx_event,
1452 UMAC_RESET_STATE_WAIT_FOR_TRIGGER,
1453 UMAC_RESET_STATE_DO_TRIGGER_RECEIVED);
1454
1455 if (status != QDF_STATUS_SUCCESS) {
1456 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1457 return status;
1458 }
1459
1460 grp_umac_reset_ctx->umac_reset_in_progress = true;
1461 grp_umac_reset_ctx->is_target_recovery = is_target_recovery;
1462
1463 /* We don't wait for the 'Umac trigger' message from all socs */
1464 grp_umac_reset_ctx->request_map = grp_umac_reset_ctx->partner_map;
1465 grp_umac_reset_ctx->response_map = grp_umac_reset_ctx->partner_map;
1466 grp_umac_reset_ctx->initiator_chip_id = dp_mlo_get_chip_id(soc);
1467 grp_umac_reset_ctx->umac_reset_count++;
1468
1469 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1470
1471 return QDF_STATUS_SUCCESS;
1472 }
1473
1474 /**
1475 * dp_umac_reset_handle_action_cb() - Function to call action callback
1476 * @soc: dp soc handle
1477 * @umac_reset_ctx: Umac reset context
1478 * @action: Action to call the callback for
1479 *
1480 * Return: QDF_STATUS status
1481 */
1482 QDF_STATUS
dp_umac_reset_handle_action_cb(struct dp_soc * soc,struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_action action)1483 dp_umac_reset_handle_action_cb(struct dp_soc *soc,
1484 struct dp_soc_umac_reset_ctx *umac_reset_ctx,
1485 enum umac_reset_action action)
1486 {
1487 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1488 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1489 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1490
1491 if (!mlo_ctx) {
1492 dp_umac_reset_debug("MLO context is Null");
1493 goto handle;
1494 }
1495
1496 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1497 qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1498
1499 qdf_atomic_set_bit(dp_mlo_get_chip_id(soc),
1500 &grp_umac_reset_ctx->request_map);
1501
1502 dp_umac_reset_debug("partner_map %u request_map %u",
1503 grp_umac_reset_ctx->partner_map,
1504 grp_umac_reset_ctx->request_map);
1505
1506 /* This logic is needed for synchronization between mlo socs */
1507 if ((grp_umac_reset_ctx->partner_map & grp_umac_reset_ctx->request_map)
1508 != grp_umac_reset_ctx->partner_map) {
1509 struct hif_softc *hif_sc = HIF_GET_SOFTC(soc->hif_handle);
1510 struct hif_umac_reset_ctx *hif_umac_reset_ctx;
1511
1512 if (!hif_sc) {
1513 hif_err("scn is null");
1514 qdf_assert_always(0);
1515 return QDF_STATUS_E_FAILURE;
1516 }
1517
1518 hif_umac_reset_ctx = &hif_sc->umac_reset_ctx;
1519
1520 /* Mark the action as pending */
1521 umac_reset_ctx->pending_action = action;
1522 /* Reschedule the tasklet and exit */
1523 tasklet_hi_schedule(&hif_umac_reset_ctx->intr_tq);
1524 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1525
1526 return QDF_STATUS_SUCCESS;
1527 }
1528
1529 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1530 umac_reset_ctx->pending_action = UMAC_RESET_ACTION_NONE;
1531
1532 handle:
1533 if (!umac_reset_ctx->rx_actions.cb[action]) {
1534 dp_umac_reset_err("rx callback is NULL");
1535 return QDF_STATUS_E_FAILURE;
1536 }
1537
1538 return umac_reset_ctx->rx_actions.cb[action](soc);
1539 }
1540
1541 /**
1542 * dp_umac_reset_post_tx_cmd() - Iterate partner socs and post Tx command
1543 * @umac_reset_ctx: UMAC reset context
1544 * @tx_cmd: Tx command to be posted
1545 *
1546 * Return: QDF status of operation
1547 */
1548 QDF_STATUS
dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_tx_cmd tx_cmd)1549 dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx *umac_reset_ctx,
1550 enum umac_reset_tx_cmd tx_cmd)
1551 {
1552 struct dp_soc *soc = container_of(umac_reset_ctx, struct dp_soc,
1553 umac_reset_ctx);
1554 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1555 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1556 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1557
1558 if (!mlo_ctx) {
1559 dp_umac_reset_post_tx_cmd_via_shmem(soc, &tx_cmd, 0);
1560 return QDF_STATUS_SUCCESS;
1561 }
1562
1563 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1564 qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1565
1566 qdf_atomic_set_bit(dp_mlo_get_chip_id(soc),
1567 &grp_umac_reset_ctx->response_map);
1568
1569 /* This logic is needed for synchronization between mlo socs */
1570 if ((grp_umac_reset_ctx->partner_map & grp_umac_reset_ctx->response_map)
1571 != grp_umac_reset_ctx->partner_map) {
1572 dp_umac_reset_debug(
1573 "Response(s) pending : expected map %u current map %u",
1574 grp_umac_reset_ctx->partner_map,
1575 grp_umac_reset_ctx->response_map);
1576
1577 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1578 return QDF_STATUS_SUCCESS;
1579 }
1580
1581 dp_umac_reset_debug(
1582 "All responses received: expected map %u current map %u",
1583 grp_umac_reset_ctx->partner_map,
1584 grp_umac_reset_ctx->response_map);
1585
1586 grp_umac_reset_ctx->response_map = 0;
1587 grp_umac_reset_ctx->request_map = 0;
1588 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1589
1590 dp_mlo_iter_ptnr_soc(be_soc, &dp_umac_reset_post_tx_cmd_via_shmem,
1591 &tx_cmd);
1592
1593 if (tx_cmd == UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE)
1594 dp_umac_reset_complete_umac_recovery(soc);
1595
1596 return QDF_STATUS_SUCCESS;
1597 }
1598
1599 /**
1600 * dp_umac_reset_initiator_check() - Check if soc is the Umac reset initiator
1601 * @soc: dp soc handle
1602 *
1603 * Return: true if the soc is initiator or false otherwise
1604 */
dp_umac_reset_initiator_check(struct dp_soc * soc)1605 bool dp_umac_reset_initiator_check(struct dp_soc *soc)
1606 {
1607 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1608 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1609
1610 if (!mlo_ctx)
1611 return true;
1612
1613 return (mlo_ctx->grp_umac_reset_ctx.initiator_chip_id ==
1614 dp_mlo_get_chip_id(soc));
1615 }
1616
1617 /**
1618 * dp_umac_reset_target_recovery_check() - Check if this is for target recovery
1619 * @soc: dp soc handle
1620 *
1621 * Return: true if the session is for target recovery or false otherwise
1622 */
dp_umac_reset_target_recovery_check(struct dp_soc * soc)1623 bool dp_umac_reset_target_recovery_check(struct dp_soc *soc)
1624 {
1625 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1626 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1627
1628 if (!mlo_ctx)
1629 return false;
1630
1631 return mlo_ctx->grp_umac_reset_ctx.is_target_recovery;
1632 }
1633
1634 /**
1635 * dp_umac_reset_is_soc_ignored() - Check if this soc is to be ignored
1636 * @soc: dp soc handle
1637 *
1638 * Return: true if the soc is ignored or false otherwise
1639 */
dp_umac_reset_is_soc_ignored(struct dp_soc * soc)1640 bool dp_umac_reset_is_soc_ignored(struct dp_soc *soc)
1641 {
1642 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1643 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1644
1645 if (!mlo_ctx)
1646 return false;
1647
1648 return !qdf_atomic_test_bit(dp_mlo_get_chip_id(soc),
1649 &mlo_ctx->grp_umac_reset_ctx.partner_map);
1650 }
1651
dp_mlo_umac_reset_stats_print(struct dp_soc * soc)1652 QDF_STATUS dp_mlo_umac_reset_stats_print(struct dp_soc *soc)
1653 {
1654 struct dp_mlo_ctxt *mlo_ctx;
1655 struct dp_soc_be *be_soc;
1656 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1657
1658 be_soc = dp_get_be_soc_from_dp_soc(soc);
1659 if (!be_soc) {
1660 dp_umac_reset_err("null be_soc");
1661 return QDF_STATUS_E_NULL_VALUE;
1662 }
1663
1664 mlo_ctx = be_soc->ml_ctxt;
1665 if (!mlo_ctx) {
1666 /* This API can be called for non-MLO SOC as well. Hence, return
1667 * the status as success when mlo_ctx is NULL.
1668 */
1669 return QDF_STATUS_SUCCESS;
1670 }
1671
1672 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1673
1674 DP_UMAC_RESET_PRINT_STATS("MLO UMAC RESET stats\n"
1675 "\t\tPartner map :%x\n"
1676 "\t\tRequest map :%x\n"
1677 "\t\tResponse map :%x\n"
1678 "\t\tIs target recovery :%d\n"
1679 "\t\tIs Umac reset inprogress :%d\n"
1680 "\t\tNumber of UMAC reset triggered:%d\n"
1681 "\t\tInitiator chip ID :%d\n",
1682 grp_umac_reset_ctx->partner_map,
1683 grp_umac_reset_ctx->request_map,
1684 grp_umac_reset_ctx->response_map,
1685 grp_umac_reset_ctx->is_target_recovery,
1686 grp_umac_reset_ctx->umac_reset_in_progress,
1687 grp_umac_reset_ctx->umac_reset_count,
1688 grp_umac_reset_ctx->initiator_chip_id);
1689
1690 return QDF_STATUS_SUCCESS;
1691 }
1692
1693 enum cdp_umac_reset_state
dp_get_umac_reset_in_progress_state(struct cdp_soc_t * psoc)1694 dp_get_umac_reset_in_progress_state(struct cdp_soc_t *psoc)
1695 {
1696 struct dp_soc_umac_reset_ctx *umac_reset_ctx;
1697 struct dp_soc *soc = (struct dp_soc *)psoc;
1698 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1699 struct dp_soc_be *be_soc = NULL;
1700 struct dp_mlo_ctxt *mlo_ctx = NULL;
1701 enum cdp_umac_reset_state umac_reset_is_inprogress;
1702
1703 if (!soc) {
1704 dp_umac_reset_err("DP SOC is null");
1705 return CDP_UMAC_RESET_INVALID_STATE;
1706 }
1707
1708 umac_reset_ctx = &soc->umac_reset_ctx;
1709
1710 be_soc = dp_get_be_soc_from_dp_soc(soc);
1711 if (be_soc)
1712 mlo_ctx = be_soc->ml_ctxt;
1713
1714 if (mlo_ctx) {
1715 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1716 umac_reset_is_inprogress =
1717 grp_umac_reset_ctx->umac_reset_in_progress;
1718 } else {
1719 umac_reset_is_inprogress = (umac_reset_ctx->current_state !=
1720 UMAC_RESET_STATE_WAIT_FOR_TRIGGER);
1721 }
1722
1723 if (umac_reset_is_inprogress)
1724 return CDP_UMAC_RESET_IN_PROGRESS;
1725
1726 /* Check if the umac reset was in progress during the buffer
1727 * window.
1728 */
1729 umac_reset_is_inprogress =
1730 ((qdf_get_log_timestamp_usecs() -
1731 umac_reset_ctx->ts.post_reset_complete_done) <=
1732 (wlan_cfg_get_umac_reset_buffer_window_ms(soc->wlan_cfg_ctx) *
1733 1000));
1734
1735 return (umac_reset_is_inprogress ?
1736 CDP_UMAC_RESET_IN_PROGRESS_DURING_BUFFER_WINDOW :
1737 CDP_UMAC_RESET_NOT_IN_PROGRESS);
1738 }
1739
1740 /**
1741 * dp_get_global_tx_desc_cleanup_flag() - Get cleanup needed flag
1742 * @soc: dp soc handle
1743 *
1744 * Return: cleanup needed/ not needed
1745 */
dp_get_global_tx_desc_cleanup_flag(struct dp_soc * soc)1746 bool dp_get_global_tx_desc_cleanup_flag(struct dp_soc *soc)
1747 {
1748 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1749 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1750 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1751 bool flag;
1752
1753 if (!mlo_ctx)
1754 return true;
1755
1756 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1757 qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1758
1759 flag = grp_umac_reset_ctx->tx_desc_pool_cleaned;
1760 if (!flag)
1761 grp_umac_reset_ctx->tx_desc_pool_cleaned = true;
1762
1763 qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock);
1764
1765 return !flag;
1766 }
1767
1768 /**
1769 * dp_reset_global_tx_desc_cleanup_flag() - Reset cleanup needed flag
1770 * @soc: dp soc handle
1771 *
1772 * Return: None
1773 */
dp_reset_global_tx_desc_cleanup_flag(struct dp_soc * soc)1774 void dp_reset_global_tx_desc_cleanup_flag(struct dp_soc *soc)
1775 {
1776 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1777 struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt;
1778 struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx;
1779
1780 if (!mlo_ctx)
1781 return;
1782
1783 grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx;
1784 grp_umac_reset_ctx->tx_desc_pool_cleaned = false;
1785 }
1786 #endif
1787
1788 struct dp_soc *
dp_get_soc_by_chip_id_be(struct dp_soc * soc,uint8_t chip_id)1789 dp_get_soc_by_chip_id_be(struct dp_soc *soc, uint8_t chip_id)
1790 {
1791 struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
1792 struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
1793 struct dp_soc *partner_soc;
1794
1795 if (!be_soc->mlo_enabled || !mlo_ctxt)
1796 return soc;
1797
1798 if (be_soc->mlo_chip_id == chip_id)
1799 return soc;
1800
1801 partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
1802 return partner_soc;
1803 }
1804