1 /*
2 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /**
19 * DOC: wlan_mgmt_txrx_rx_reo.c
20 * This file contains mgmt rx re-ordering related function definitions
21 */
22
23 #include "wlan_mgmt_txrx_rx_reo_i.h"
24 #include <wlan_mgmt_txrx_rx_reo_tgt_api.h>
25 #include "wlan_mgmt_txrx_main_i.h"
26 #include <qdf_util.h>
27 #include <wlan_mlo_mgr_cmn.h>
28 #include <wlan_mlo_mgr_setup.h>
29 #include <qdf_platform.h>
30 #include <qdf_types.h>
31
32 static struct mgmt_rx_reo_context *g_rx_reo_ctx[WLAN_MAX_MLO_GROUPS];
33
34 #define mgmt_rx_reo_get_context(_grp_id) (g_rx_reo_ctx[_grp_id])
35 #define mgmt_rx_reo_set_context(grp_id, c) (g_rx_reo_ctx[grp_id] = c)
36
37 #define MGMT_RX_REO_PKT_CTR_HALF_RANGE (0x8000)
38 #define MGMT_RX_REO_PKT_CTR_FULL_RANGE (MGMT_RX_REO_PKT_CTR_HALF_RANGE << 1)
39
40 /**
41 * wlan_mgmt_rx_reo_get_ctx_from_pdev - Get MGMT Rx REO Context from pdev
42 * @pdev: Pointer to pdev structure object
43 *
44 * API to get the MGMT RX reo context of the pdev using the appropriate
45 * MLO group id.
46 *
47 * Return: Mgmt rx reo context for the pdev
48 */
49
50 static inline struct mgmt_rx_reo_context*
wlan_mgmt_rx_reo_get_ctx_from_pdev(struct wlan_objmgr_pdev * pdev)51 wlan_mgmt_rx_reo_get_ctx_from_pdev(struct wlan_objmgr_pdev *pdev)
52 {
53 uint8_t ml_grp_id;
54
55 ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
56 if (ml_grp_id >= WLAN_MAX_MLO_GROUPS) {
57 mgmt_rx_reo_err("REO context - Invalid ML Group ID");
58 return NULL;
59 }
60
61 return mgmt_rx_reo_get_context(ml_grp_id);
62 }
63
64 /**
65 * mgmt_rx_reo_compare_pkt_ctrs_gte() - Compare given mgmt packet counters
66 * @ctr1: Management packet counter1
67 * @ctr2: Management packet counter2
68 *
69 * We can't directly use the comparison operator here because the counters can
70 * overflow. But these counters have a property that the difference between
71 * them can never be greater than half the range of the data type.
72 * We can make use of this condition to detect which one is actually greater.
73 *
74 * Return: true if @ctr1 is greater than or equal to @ctr2, else false
75 */
76 static inline bool
mgmt_rx_reo_compare_pkt_ctrs_gte(uint16_t ctr1,uint16_t ctr2)77 mgmt_rx_reo_compare_pkt_ctrs_gte(uint16_t ctr1, uint16_t ctr2)
78 {
79 uint16_t delta = ctr1 - ctr2;
80
81 return delta <= MGMT_RX_REO_PKT_CTR_HALF_RANGE;
82 }
83
84 /**
85 * mgmt_rx_reo_subtract_pkt_ctrs() - Subtract given mgmt packet counters
86 * @ctr1: Management packet counter1
87 * @ctr2: Management packet counter2
88 *
89 * We can't directly use the subtract operator here because the counters can
90 * overflow. But these counters have a property that the difference between
91 * them can never be greater than half the range of the data type.
92 * We can make use of this condition to detect whichone is actually greater and
93 * return the difference accordingly.
94 *
95 * Return: Difference between @ctr1 and @crt2
96 */
97 static inline int
mgmt_rx_reo_subtract_pkt_ctrs(uint16_t ctr1,uint16_t ctr2)98 mgmt_rx_reo_subtract_pkt_ctrs(uint16_t ctr1, uint16_t ctr2)
99 {
100 uint16_t delta = ctr1 - ctr2;
101
102 /**
103 * if delta is greater than half the range (i.e, ctr1 is actually
104 * smaller than ctr2), then the result should be a negative number.
105 * subtracting the entire range should give the correct value.
106 */
107 if (delta > MGMT_RX_REO_PKT_CTR_HALF_RANGE)
108 return delta - MGMT_RX_REO_PKT_CTR_FULL_RANGE;
109
110 return delta;
111 }
112
113 #define MGMT_RX_REO_GLOBAL_TS_HALF_RANGE (0x80000000)
114 /**
115 * mgmt_rx_reo_compare_global_timestamps_gte()-Compare given global timestamps
116 * @ts1: Global timestamp1
117 * @ts2: Global timestamp2
118 *
119 * We can't directly use the comparison operator here because the timestamps can
120 * overflow. But these timestamps have a property that the difference between
121 * them can never be greater than half the range of the data type.
122 * We can make use of this condition to detect which one is actually greater.
123 *
124 * Return: true if @ts1 is greater than or equal to @ts2, else false
125 */
126 static inline bool
mgmt_rx_reo_compare_global_timestamps_gte(uint32_t ts1,uint32_t ts2)127 mgmt_rx_reo_compare_global_timestamps_gte(uint32_t ts1, uint32_t ts2)
128 {
129 uint32_t delta = ts1 - ts2;
130
131 return delta <= MGMT_RX_REO_GLOBAL_TS_HALF_RANGE;
132 }
133
134 #ifdef WLAN_MGMT_RX_REO_ERROR_HANDLING
135 /**
136 * handle_snapshot_sanity_failures() - Handle snapshot sanity failure
137 * @desc: Pointer to frame descriptor
138 * @link: Link ID
139 *
140 * API to handle snapshot sanity failure. Host drops management frames which
141 * results in snapshot sanity failure.
142 *
143 * Return: QDF_STATUS
144 */
145 static QDF_STATUS
handle_snapshot_sanity_failures(struct mgmt_rx_reo_frame_descriptor * desc,uint8_t link)146 handle_snapshot_sanity_failures(struct mgmt_rx_reo_frame_descriptor *desc,
147 uint8_t link)
148 {
149 if (!desc) {
150 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
151 return QDF_STATUS_E_NULL_VALUE;
152 }
153
154 mgmt_rx_reo_debug_rl("Snapshot sanity check for link %u failed", link);
155
156 desc->drop = true;
157 desc->drop_reason = MGMT_RX_REO_SNAPSHOT_SANITY_FAILURE;
158
159 return QDF_STATUS_SUCCESS;
160 }
161
162 /**
163 * handle_out_of_order_pkt_ctr() - Handle management frames with out of order
164 * packet counter values
165 * @desc: Pointer to frame descriptor
166 * @host_ss: Pointer to host snapshot
167 *
168 * API to handle management frames with out of order packet counter values.
169 * This API implements the design choice to drop management frames with packet
170 * counter value less than than or equal to the last management frame received
171 * in the same link.
172 *
173 * Return: QDF_STATUS
174 */
175 static QDF_STATUS
handle_out_of_order_pkt_ctr(struct mgmt_rx_reo_frame_descriptor * desc,struct mgmt_rx_reo_snapshot_params * host_ss)176 handle_out_of_order_pkt_ctr(struct mgmt_rx_reo_frame_descriptor *desc,
177 struct mgmt_rx_reo_snapshot_params *host_ss)
178 {
179 if (!desc) {
180 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
181 return QDF_STATUS_E_NULL_VALUE;
182 }
183
184 if (!host_ss) {
185 mgmt_rx_reo_err("Mgmt Rx REO host snapshot is null");
186 return QDF_STATUS_E_NULL_VALUE;
187 }
188
189 mgmt_rx_reo_debug_rl("Cur frame ctr <= last frame ctr for link = %u",
190 mgmt_rx_reo_get_link_id(desc->rx_params));
191
192 desc->drop = true;
193 if (mgmt_rx_reo_get_pkt_counter(desc->rx_params) ==
194 host_ss->mgmt_pkt_ctr)
195 desc->drop_reason = MGMT_RX_REO_DUPLICATE_PKT_CTR;
196 else
197 desc->drop_reason = MGMT_RX_REO_OUT_OF_ORDER_PKT_CTR;
198
199 return QDF_STATUS_SUCCESS;
200 }
201
202 /**
203 * check_and_handle_zero_frame_duration() - Check and handle zero duration error
204 * @pdev: Pointer to pdev object
205 * @desc: Pointer to frame descriptor
206 *
207 * API to check for zero duration management frames. Host will be able to
208 * reorder such frames with the limitation that parallel rx detection may fail.
209 * Hence don't drop management frames with zero duration.
210 *
211 * Return: QDF_STATUS
212 */
213 static QDF_STATUS
check_and_handle_zero_frame_duration(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_frame_descriptor * desc)214 check_and_handle_zero_frame_duration(struct wlan_objmgr_pdev *pdev,
215 struct mgmt_rx_reo_frame_descriptor *desc)
216 {
217 struct mgmt_rx_reo_params *reo_params;
218
219 if (!desc) {
220 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
221 return QDF_STATUS_E_NULL_VALUE;
222 }
223
224 if (!desc->rx_params) {
225 mgmt_rx_reo_err("Mgmt Rx params is null");
226 return QDF_STATUS_E_NULL_VALUE;
227 }
228
229 reo_params = desc->rx_params->reo_params;
230 if (!reo_params) {
231 mgmt_rx_reo_err("Mgmt Rx REO params is NULL");
232 return QDF_STATUS_E_NULL_VALUE;
233 }
234
235 if (desc->type == MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME &&
236 !mgmt_rx_reo_get_duration_us(desc->rx_params)) {
237 mgmt_rx_reo_debug_rl("0 dur: link= %u,valid= %u,ctr= %u,ts= %u",
238 reo_params->link_id, reo_params->valid,
239 reo_params->mgmt_pkt_ctr,
240 reo_params->global_timestamp);
241 }
242
243 return QDF_STATUS_SUCCESS;
244 }
245
246 /**
247 * check_and_handle_invalid_reo_params() - Check and handle invalid reo
248 * parameters error
249 * @desc: Pointer to frame descriptor
250 *
251 * API to check for invalid reo parameter error. Host won't be able to reorder
252 * this frame and hence drop this frame.
253 *
254 * Return: QDF_STATUS
255 */
256 static QDF_STATUS
check_and_handle_invalid_reo_params(struct mgmt_rx_reo_frame_descriptor * desc)257 check_and_handle_invalid_reo_params(struct mgmt_rx_reo_frame_descriptor *desc)
258 {
259 struct mgmt_rx_reo_params *reo_params;
260
261 if (!desc) {
262 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
263 return QDF_STATUS_E_NULL_VALUE;
264 }
265
266 if (!desc->rx_params) {
267 mgmt_rx_reo_err("Mgmt Rx params is null");
268 return QDF_STATUS_E_NULL_VALUE;
269 }
270
271 reo_params = desc->rx_params->reo_params;
272 if (!reo_params) {
273 mgmt_rx_reo_err("Mgmt Rx REO params is NULL");
274 return QDF_STATUS_E_NULL_VALUE;
275 }
276
277 if (!reo_params->valid) {
278 mgmt_rx_reo_debug_rl("Invalid param: link= %u, ctr= %u, ts= %u",
279 reo_params->link_id,
280 reo_params->mgmt_pkt_ctr,
281 reo_params->global_timestamp);
282 desc->drop = true;
283 desc->drop_reason = MGMT_RX_REO_INVALID_REO_PARAMS;
284
285 return QDF_STATUS_E_FAILURE;
286 }
287
288 return QDF_STATUS_SUCCESS;
289 }
290 #else
291 /**
292 * handle_snapshot_sanity_failures() - Handle snapshot sanity failure
293 * @desc: Pointer to frame descriptor
294 * @link: Link ID
295 *
296 * API to handle snapshot sanity failure. Host drops management frames which
297 * results in snapshot sanity failure.
298 *
299 * Return: QDF_STATUS
300 */
301 static QDF_STATUS
handle_snapshot_sanity_failures(struct mgmt_rx_reo_frame_descriptor * desc,uint8_t link)302 handle_snapshot_sanity_failures(struct mgmt_rx_reo_frame_descriptor *desc,
303 uint8_t link)
304 {
305 if (!desc) {
306 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
307 return QDF_STATUS_E_NULL_VALUE;
308 }
309
310 mgmt_rx_reo_err_rl("Snapshot sanity check for link %u failed", link);
311
312 desc->drop = true;
313 desc->drop_reason = MGMT_RX_REO_SNAPSHOT_SANITY_FAILURE;
314
315 return QDF_STATUS_SUCCESS;
316 }
317
318 /**
319 * handle_out_of_order_pkt_ctr() - Handle management frames with out of order
320 * packet counter values
321 * @desc: Pointer to frame descriptor
322 * @host_ss: Pointer to host snapshot
323 *
324 * API to handle management frames with out of order packet counter values.
325 * This API implements the design choice to assert on reception of management
326 * frames with packet counter value less than than or equal to the last
327 * management frame received in the same link.
328 *
329 * Return: QDF_STATUS
330 */
331 static QDF_STATUS
handle_out_of_order_pkt_ctr(struct mgmt_rx_reo_frame_descriptor * desc,struct mgmt_rx_reo_snapshot_params * host_ss)332 handle_out_of_order_pkt_ctr(struct mgmt_rx_reo_frame_descriptor *desc,
333 struct mgmt_rx_reo_snapshot_params *host_ss)
334 {
335 if (!desc) {
336 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
337 return QDF_STATUS_E_NULL_VALUE;
338 }
339
340 mgmt_rx_reo_err_rl("Cur frame ctr <= last frame ctr for link = %u",
341 mgmt_rx_reo_get_link_id(desc->rx_params));
342
343 return QDF_STATUS_E_FAILURE;
344 }
345
346 /**
347 * check_and_handle_zero_frame_duration() - Check and handle zero duration error
348 * @pdev: Pointer to pdev object
349 * @desc: Pointer to frame descriptor
350 *
351 * API to check for zero duration management frames and assert.
352 *
353 * Return: QDF_STATUS
354 */
355 static QDF_STATUS
check_and_handle_zero_frame_duration(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_frame_descriptor * desc)356 check_and_handle_zero_frame_duration(struct wlan_objmgr_pdev *pdev,
357 struct mgmt_rx_reo_frame_descriptor *desc)
358 {
359 struct mgmt_rx_reo_params *reo_params;
360
361 if (!desc) {
362 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
363 return QDF_STATUS_E_NULL_VALUE;
364 }
365
366 if (!desc->rx_params) {
367 mgmt_rx_reo_err("Mgmt Rx params is null");
368 return QDF_STATUS_E_NULL_VALUE;
369 }
370
371 reo_params = desc->rx_params->reo_params;
372 if (!reo_params) {
373 mgmt_rx_reo_err("Mgmt Rx REO params is NULL");
374 return QDF_STATUS_E_NULL_VALUE;
375 }
376
377 if (desc->type == MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME &&
378 !mgmt_rx_reo_get_duration_us(desc->rx_params)) {
379 mgmt_rx_reo_err_rl("0 dur: link= %u,valid= %u,ctr= %u,ts= %u",
380 reo_params->link_id, reo_params->valid,
381 reo_params->mgmt_pkt_ctr,
382 reo_params->global_timestamp);
383 mgmt_rx_reo_err("Triggering self recovery, zero duration pkt");
384 qdf_trigger_self_recovery(wlan_pdev_get_psoc(pdev),
385 QDF_MGMT_RX_REO_ZERO_DURATION_PKT);
386
387 return QDF_STATUS_E_FAILURE;
388 }
389
390 return QDF_STATUS_SUCCESS;
391 }
392
393 /**
394 * check_and_handle_invalid_reo_params() - Check and handle invalid reo
395 * parameters error
396 * @desc: Pointer to frame descriptor
397 *
398 * API to check for invalid reo parameter error. Host won't be able to reorder
399 * this frame and hence drop this frame.
400 *
401 * Return: QDF_STATUS
402 */
403 static QDF_STATUS
check_and_handle_invalid_reo_params(struct mgmt_rx_reo_frame_descriptor * desc)404 check_and_handle_invalid_reo_params(struct mgmt_rx_reo_frame_descriptor *desc)
405 {
406 struct mgmt_rx_reo_params *reo_params;
407
408 if (!desc) {
409 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor is null");
410 return QDF_STATUS_E_NULL_VALUE;
411 }
412
413 if (!desc->rx_params) {
414 mgmt_rx_reo_err("Mgmt Rx params is null");
415 return QDF_STATUS_E_NULL_VALUE;
416 }
417
418 reo_params = desc->rx_params->reo_params;
419 if (!reo_params) {
420 mgmt_rx_reo_err("Mgmt Rx REO params is NULL");
421 return QDF_STATUS_E_NULL_VALUE;
422 }
423
424 if (!reo_params->valid) {
425 mgmt_rx_reo_err_rl("Invalid params: link= %u, ctr= %u, ts= %u",
426 reo_params->link_id,
427 reo_params->mgmt_pkt_ctr,
428 reo_params->global_timestamp);
429 desc->drop = true;
430 desc->drop_reason = MGMT_RX_REO_INVALID_REO_PARAMS;
431
432 return QDF_STATUS_E_FAILURE;
433 }
434
435 return QDF_STATUS_SUCCESS;
436 }
437 #endif /* WLAN_MGMT_RX_REO_ERROR_HANDLING */
438
439 /**
440 * mgmt_rx_reo_is_stale_frame()- API to check whether the given management frame
441 * is stale
442 * @last_delivered_frame: pointer to the info of the last frame delivered to
443 * upper layer
444 * @frame_desc: pointer to frame descriptor
445 *
446 * This API checks whether the current management frame under processing is
447 * stale. Any frame older than the last frame delivered to upper layer is a
448 * stale frame. This could happen when we have to deliver frames out of order
449 * due to time out or list size limit. The frames which arrive late at host and
450 * with time stamp lesser than the last delivered frame are stale frames and
451 * they need to be handled differently.
452 *
453 * Return: QDF_STATUS. On success "is_stale" and "is_parallel_rx" members of
454 * @frame_desc will be filled with proper values.
455 */
456 static QDF_STATUS
mgmt_rx_reo_is_stale_frame(struct mgmt_rx_reo_frame_info * last_delivered_frame,struct mgmt_rx_reo_frame_descriptor * frame_desc)457 mgmt_rx_reo_is_stale_frame(
458 struct mgmt_rx_reo_frame_info *last_delivered_frame,
459 struct mgmt_rx_reo_frame_descriptor *frame_desc)
460 {
461 uint32_t cur_frame_start_ts;
462 uint32_t cur_frame_end_ts;
463 uint32_t last_delivered_frame_start_ts;
464 uint32_t last_delivered_frame_end_ts;
465
466 if (!last_delivered_frame) {
467 mgmt_rx_reo_err("Last delivered frame info is null");
468 return QDF_STATUS_E_NULL_VALUE;
469 }
470
471 if (!frame_desc) {
472 mgmt_rx_reo_err("Frame descriptor is null");
473 return QDF_STATUS_E_NULL_VALUE;
474 }
475
476 frame_desc->is_stale = false;
477 frame_desc->is_parallel_rx = false;
478 frame_desc->last_delivered_frame = *last_delivered_frame;
479
480 if (!frame_desc->reo_required)
481 return QDF_STATUS_SUCCESS;
482
483 if (!last_delivered_frame->valid)
484 return QDF_STATUS_SUCCESS;
485
486 cur_frame_start_ts = mgmt_rx_reo_get_start_ts(frame_desc->rx_params);
487 cur_frame_end_ts = mgmt_rx_reo_get_end_ts(frame_desc->rx_params);
488 last_delivered_frame_start_ts =
489 last_delivered_frame->reo_params.start_timestamp;
490 last_delivered_frame_end_ts =
491 last_delivered_frame->reo_params.end_timestamp;
492
493 frame_desc->is_stale =
494 !mgmt_rx_reo_compare_global_timestamps_gte(cur_frame_start_ts,
495 last_delivered_frame_start_ts);
496
497 if (mgmt_rx_reo_compare_global_timestamps_gte
498 (last_delivered_frame_start_ts, cur_frame_start_ts) &&
499 mgmt_rx_reo_compare_global_timestamps_gte
500 (cur_frame_end_ts, last_delivered_frame_end_ts)) {
501 frame_desc->is_parallel_rx = true;
502 frame_desc->is_stale = false;
503 }
504
505 return QDF_STATUS_SUCCESS;
506 }
507
508 QDF_STATUS
mgmt_rx_reo_validate_mlo_link_info(struct wlan_objmgr_psoc * psoc)509 mgmt_rx_reo_validate_mlo_link_info(struct wlan_objmgr_psoc *psoc)
510 {
511 uint16_t valid_link_bitmap_shmem;
512 uint16_t valid_link_bitmap;
513 int8_t num_active_links_shmem;
514 int8_t num_active_links;
515 uint8_t grp_id = 0;
516 QDF_STATUS status;
517
518 if (!psoc) {
519 mgmt_rx_reo_err("psoc is null");
520 return QDF_STATUS_E_NULL_VALUE;
521 }
522
523 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_psoc(psoc))
524 return QDF_STATUS_SUCCESS;
525
526 status = tgt_mgmt_rx_reo_get_num_active_hw_links(psoc,
527 &num_active_links_shmem);
528 if (QDF_IS_STATUS_ERROR(status)) {
529 mgmt_rx_reo_err("Failed to get number of active MLO HW links");
530 return QDF_STATUS_E_FAILURE;
531 }
532
533 if (num_active_links_shmem <= 0) {
534 mgmt_rx_reo_err("Invalid number of active links from shmem %d",
535 num_active_links_shmem);
536 return QDF_STATUS_E_INVAL;
537 }
538
539 if (!mlo_psoc_get_grp_id(psoc, &grp_id)) {
540 mgmt_rx_reo_err("Failed to get valid MLO Group id");
541 return QDF_STATUS_E_INVAL;
542 }
543
544 num_active_links = wlan_mlo_get_num_active_links(grp_id);
545 if (num_active_links <= 0) {
546 mgmt_rx_reo_err("Invalid number of active links %d",
547 num_active_links);
548 return QDF_STATUS_E_INVAL;
549 }
550
551 if (num_active_links_shmem != num_active_links) {
552 mgmt_rx_reo_err("Mismatch in active links %d and %d",
553 num_active_links_shmem, num_active_links);
554 return QDF_STATUS_E_INVAL;
555 }
556
557 status = tgt_mgmt_rx_reo_get_valid_hw_link_bitmap(psoc,
558 &valid_link_bitmap_shmem);
559 if (QDF_IS_STATUS_ERROR(status)) {
560 mgmt_rx_reo_err("Failed to get valid MLO HW link bitmap");
561 return QDF_STATUS_E_INVAL;
562 }
563
564 if (!valid_link_bitmap_shmem) {
565 mgmt_rx_reo_err("Valid link bitmap from shmem is 0");
566 return QDF_STATUS_E_INVAL;
567 }
568
569 valid_link_bitmap = wlan_mlo_get_valid_link_bitmap(grp_id);
570 if (!valid_link_bitmap) {
571 mgmt_rx_reo_err("Valid link bitmap is 0");
572 return QDF_STATUS_E_INVAL;
573 }
574
575 if (valid_link_bitmap_shmem != valid_link_bitmap) {
576 mgmt_rx_reo_err("Mismatch in valid link bit map 0x%x and 0x%x",
577 valid_link_bitmap_shmem, valid_link_bitmap);
578 return QDF_STATUS_E_INVAL;
579 }
580
581 return QDF_STATUS_SUCCESS;
582 }
583
584 #ifndef WLAN_MGMT_RX_REO_SIM_SUPPORT
585 /**
586 * mgmt_rx_reo_is_valid_link() - Check whether the given HW link is valid
587 * @link_id: Link id to be checked
588 * @grp_id: MLO Group id which it belongs to
589 *
590 * Return: true if @link_id is a valid link else false
591 */
592 static bool
mgmt_rx_reo_is_valid_link(uint8_t link_id,uint8_t grp_id)593 mgmt_rx_reo_is_valid_link(uint8_t link_id, uint8_t grp_id)
594 {
595 uint16_t valid_hw_link_bitmap;
596
597 if (link_id >= MAX_MLO_LINKS) {
598 mgmt_rx_reo_err("Invalid link id %u", link_id);
599 return false;
600 }
601
602 valid_hw_link_bitmap = wlan_mlo_get_valid_link_bitmap(grp_id);
603 if (!valid_hw_link_bitmap) {
604 mgmt_rx_reo_err("Valid HW link bitmap is zero");
605 return false;
606 }
607
608 return (valid_hw_link_bitmap & (1 << link_id));
609 }
610
611 /**
612 * mgmt_rx_reo_get_num_mlo_links() - Get number of MLO HW links active in the
613 * system
614 * @reo_context: Pointer to reo context object
615 * @grp_id: MLO group id which it belongs to
616 *
617 * Return: On success returns number of active MLO HW links. On failure
618 * returns WLAN_MLO_INVALID_NUM_LINKS.
619 */
620 static int8_t
mgmt_rx_reo_get_num_mlo_links(struct mgmt_rx_reo_context * reo_context,uint8_t grp_id)621 mgmt_rx_reo_get_num_mlo_links(struct mgmt_rx_reo_context *reo_context,
622 uint8_t grp_id)
623 {
624 if (!reo_context) {
625 mgmt_rx_reo_err("Mgmt reo context is null");
626 return WLAN_MLO_INVALID_NUM_LINKS;
627 }
628
629 return wlan_mlo_get_num_active_links(grp_id);
630 }
631
632 static QDF_STATUS
mgmt_rx_reo_handle_potential_premature_delivery(struct mgmt_rx_reo_context * reo_context,uint32_t global_timestamp)633 mgmt_rx_reo_handle_potential_premature_delivery(
634 struct mgmt_rx_reo_context *reo_context,
635 uint32_t global_timestamp)
636 {
637 return QDF_STATUS_SUCCESS;
638 }
639
640 static QDF_STATUS
mgmt_rx_reo_handle_stale_frame(struct mgmt_rx_reo_list * reo_list,struct mgmt_rx_reo_frame_descriptor * desc)641 mgmt_rx_reo_handle_stale_frame(struct mgmt_rx_reo_list *reo_list,
642 struct mgmt_rx_reo_frame_descriptor *desc)
643 {
644 return QDF_STATUS_SUCCESS;
645 }
646 #else
647 /**
648 * mgmt_rx_reo_sim_is_valid_link() - Check whether the given HW link is valid
649 * @sim_context: Pointer to reo simulation context object
650 * @link_id: Link id to be checked
651 *
652 * Return: true if @link_id is a valid link, else false
653 */
654 static bool
mgmt_rx_reo_sim_is_valid_link(struct mgmt_rx_reo_sim_context * sim_context,uint8_t link_id)655 mgmt_rx_reo_sim_is_valid_link(struct mgmt_rx_reo_sim_context *sim_context,
656 uint8_t link_id)
657 {
658 bool is_valid_link = false;
659
660 if (!sim_context) {
661 mgmt_rx_reo_err("Mgmt reo sim context is null");
662 return false;
663 }
664
665 if (link_id >= MAX_MLO_LINKS) {
666 mgmt_rx_reo_err("Invalid link id %u", link_id);
667 return false;
668 }
669
670 qdf_spin_lock(&sim_context->link_id_to_pdev_map.lock);
671
672 if (sim_context->link_id_to_pdev_map.map[link_id])
673 is_valid_link = true;
674
675 qdf_spin_unlock(&sim_context->link_id_to_pdev_map.lock);
676
677 return is_valid_link;
678 }
679
680 /**
681 * mgmt_rx_reo_is_valid_link() - Check whether the given HW link is valid
682 * @ml_grp_id: MLO Group id on which the Link ID belongs to
683 * @link_id: HW Link ID to be verified
684 *
685 * Return: true if @link_id is a valid link else false
686 */
687 static bool
mgmt_rx_reo_is_valid_link(uint8_t ml_grp_id,uint8_t link_id)688 mgmt_rx_reo_is_valid_link(uint8_t ml_grp_id, uint8_t link_id)
689 {
690 struct mgmt_rx_reo_context *reo_context;
691
692 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
693
694 if (!reo_context) {
695 mgmt_rx_reo_err("Mgmt reo context is null");
696 return false;
697 }
698
699 return mgmt_rx_reo_sim_is_valid_link(&reo_context->sim_context,
700 link_id);
701 }
702
703 /**
704 * mgmt_rx_reo_sim_get_num_mlo_links() - Get number of MLO HW links from the reo
705 * simulation context object
706 * @sim_context: Pointer to reo simulation context object
707 *
708 * Number of MLO links will be equal to number of pdevs in the
709 * system. In case of simulation all the pdevs are assumed
710 * to have MLO capability.
711 *
712 * Return: On success returns number of MLO HW links. On failure
713 * returns WLAN_MLO_INVALID_NUM_LINKS.
714 */
715 static int8_t
mgmt_rx_reo_sim_get_num_mlo_links(struct mgmt_rx_reo_sim_context * sim_context)716 mgmt_rx_reo_sim_get_num_mlo_links(struct mgmt_rx_reo_sim_context *sim_context)
717 {
718 uint8_t num_mlo_links;
719
720 if (!sim_context) {
721 mgmt_rx_reo_err("Mgmt reo simulation context is null");
722 return WLAN_MLO_INVALID_NUM_LINKS;
723 }
724
725 qdf_spin_lock(&sim_context->link_id_to_pdev_map.lock);
726
727 num_mlo_links = sim_context->link_id_to_pdev_map.num_mlo_links;
728
729 qdf_spin_unlock(&sim_context->link_id_to_pdev_map.lock);
730
731 return num_mlo_links;
732 }
733
734 /**
735 * mgmt_rx_reo_get_num_mlo_links() - Get number of MLO links from the reo
736 * context object
737 * @reo_context: Pointer to reo context object
738 * @grp_id: MLO Group id which it belongs to
739 *
740 * Return: On success returns number of MLO HW links. On failure
741 * returns WLAN_MLO_INVALID_NUM_LINKS.
742 */
743 static int8_t
mgmt_rx_reo_get_num_mlo_links(struct mgmt_rx_reo_context * reo_context,uint8_t grp_id)744 mgmt_rx_reo_get_num_mlo_links(struct mgmt_rx_reo_context *reo_context,
745 uint8_t grp_id)
746 {
747 if (!reo_context) {
748 mgmt_rx_reo_err("Mgmt reo context is null");
749 return WLAN_MLO_INVALID_NUM_LINKS;
750 }
751
752 return mgmt_rx_reo_sim_get_num_mlo_links(&reo_context->sim_context);
753 }
754
755 /**
756 * mgmt_rx_reo_sim_get_context() - Helper API to get the management
757 * rx reorder simulation context
758 * @ml_grp_id: MLO group id for the rx reordering
759 *
760 * Return: On success returns the pointer to management rx reorder
761 * simulation context. On failure returns NULL.
762 */
763 static struct mgmt_rx_reo_sim_context *
mgmt_rx_reo_sim_get_context(uint8_t ml_grp_id)764 mgmt_rx_reo_sim_get_context(uint8_t ml_grp_id)
765 {
766 struct mgmt_rx_reo_context *reo_context;
767
768 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
769 if (!reo_context) {
770 mgmt_rx_reo_err("Mgmt reo context is null");
771 return NULL;
772 }
773
774 return &reo_context->sim_context;
775 }
776
777 int8_t
mgmt_rx_reo_sim_get_mlo_link_id_from_pdev(struct wlan_objmgr_pdev * pdev)778 mgmt_rx_reo_sim_get_mlo_link_id_from_pdev(struct wlan_objmgr_pdev *pdev)
779 {
780 struct mgmt_rx_reo_sim_context *sim_context;
781 int8_t link_id;
782
783 sim_context = mgmt_rx_reo_sim_get_context();
784 if (!sim_context) {
785 mgmt_rx_reo_err("Mgmt reo simulation context is null");
786 return MGMT_RX_REO_INVALID_LINK;
787 }
788
789 qdf_spin_lock(&sim_context->link_id_to_pdev_map.lock);
790
791 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++)
792 if (sim_context->link_id_to_pdev_map.map[link_id] == pdev)
793 break;
794
795 /* pdev is not found in map */
796 if (link_id == MAX_MLO_LINKS)
797 link_id = MGMT_RX_REO_INVALID_LINK;
798
799 qdf_spin_unlock(&sim_context->link_id_to_pdev_map.lock);
800
801 return link_id;
802 }
803
804 struct wlan_objmgr_pdev *
mgmt_rx_reo_sim_get_pdev_from_mlo_link_id(uint8_t mlo_link_id,wlan_objmgr_ref_dbgid refdbgid)805 mgmt_rx_reo_sim_get_pdev_from_mlo_link_id(uint8_t mlo_link_id,
806 wlan_objmgr_ref_dbgid refdbgid)
807 {
808 struct mgmt_rx_reo_sim_context *sim_context;
809 struct wlan_objmgr_pdev *pdev;
810 QDF_STATUS status;
811
812 sim_context = mgmt_rx_reo_sim_get_context();
813 if (!sim_context) {
814 mgmt_rx_reo_err("Mgmt reo simulation context is null");
815 return NULL;
816 }
817
818 if (mlo_link_id >= MAX_MLO_LINKS) {
819 mgmt_rx_reo_err("Invalid link id %u", mlo_link_id);
820 return NULL;
821 }
822
823 qdf_spin_lock(&sim_context->link_id_to_pdev_map.lock);
824
825 pdev = sim_context->link_id_to_pdev_map.map[mlo_link_id];
826 status = wlan_objmgr_pdev_try_get_ref(pdev, refdbgid);
827 if (QDF_IS_STATUS_ERROR(status)) {
828 mgmt_rx_reo_err("Failed to get pdev reference");
829 return NULL;
830 }
831
832 qdf_spin_unlock(&sim_context->link_id_to_pdev_map.lock);
833
834 return pdev;
835 }
836
837 /**
838 * mgmt_rx_reo_handle_potential_premature_delivery - Helper API to handle
839 * premature delivery.
840 * @reo_context: Pointer to reorder list
841 * @global_timestamp: Global time stamp of the current management frame
842 *
843 * Sometimes we have to deliver a management frame to the upper layers even
844 * before its wait count reaching zero. This is called premature delivery.
845 * Premature delivery could happen due to time out or reorder list overflow.
846 *
847 * Return: QDF_STATUS
848 */
849 static QDF_STATUS
mgmt_rx_reo_handle_potential_premature_delivery(struct mgmt_rx_reo_context * reo_context,uint32_t global_timestamp)850 mgmt_rx_reo_handle_potential_premature_delivery(
851 struct mgmt_rx_reo_context *reo_context,
852 uint32_t global_timestamp)
853 {
854 qdf_list_t stale_frame_list_temp;
855 QDF_STATUS status;
856 struct mgmt_rx_reo_pending_frame_list_entry *latest_stale_frame = NULL;
857 struct mgmt_rx_reo_pending_frame_list_entry *cur_entry;
858 struct mgmt_rx_reo_sim_context *sim_context;
859 struct mgmt_rx_reo_master_frame_list *master_frame_list;
860
861 if (!reo_context)
862 return QDF_STATUS_E_NULL_VALUE;
863
864 sim_context = &reo_context->sim_context;
865 master_frame_list = &sim_context->master_frame_list;
866
867 qdf_spin_lock(&master_frame_list->lock);
868
869 qdf_list_for_each(&master_frame_list->pending_list, cur_entry, node) {
870 if (cur_entry->params.global_timestamp == global_timestamp)
871 break;
872
873 latest_stale_frame = cur_entry;
874 }
875
876 if (latest_stale_frame) {
877 qdf_list_create(&stale_frame_list_temp,
878 MGMT_RX_REO_SIM_STALE_FRAME_TEMP_LIST_MAX_SIZE);
879
880 status = qdf_list_split(&stale_frame_list_temp,
881 &master_frame_list->pending_list,
882 &latest_stale_frame->node);
883 if (QDF_IS_STATUS_ERROR(status))
884 goto exit_unlock_master_frame_list;
885
886 status = qdf_list_join(&master_frame_list->stale_list,
887 &stale_frame_list_temp);
888 if (QDF_IS_STATUS_ERROR(status))
889 goto exit_unlock_master_frame_list;
890 }
891
892 status = QDF_STATUS_SUCCESS;
893
894 exit_unlock_master_frame_list:
895 qdf_spin_unlock(&master_frame_list->lock);
896
897 return status;
898 }
899
900 /**
901 * mgmt_rx_reo_sim_remove_frame_from_stale_list() - Removes frame from the
902 * stale management frame list
903 * @master_frame_list: pointer to master management frame list
904 * @reo_params: pointer to reo params
905 *
906 * This API removes frames from the stale management frame list.
907 *
908 * Return: QDF_STATUS of operation
909 */
910 static QDF_STATUS
mgmt_rx_reo_sim_remove_frame_from_stale_list(struct mgmt_rx_reo_master_frame_list * master_frame_list,const struct mgmt_rx_reo_params * reo_params)911 mgmt_rx_reo_sim_remove_frame_from_stale_list(
912 struct mgmt_rx_reo_master_frame_list *master_frame_list,
913 const struct mgmt_rx_reo_params *reo_params)
914 {
915 struct mgmt_rx_reo_stale_frame_list_entry *cur_entry;
916 struct mgmt_rx_reo_stale_frame_list_entry *matching_entry = NULL;
917 QDF_STATUS status;
918
919 if (!master_frame_list || !reo_params)
920 return QDF_STATUS_E_NULL_VALUE;
921
922 qdf_spin_lock(&master_frame_list->lock);
923
924 /**
925 * Stale frames can come in any order at host. Do a linear search and
926 * remove the matching entry.
927 */
928 qdf_list_for_each(&master_frame_list->stale_list, cur_entry, node) {
929 if (cur_entry->params.link_id == reo_params->link_id &&
930 cur_entry->params.mgmt_pkt_ctr == reo_params->mgmt_pkt_ctr &&
931 cur_entry->params.global_timestamp ==
932 reo_params->global_timestamp) {
933 matching_entry = cur_entry;
934 break;
935 }
936 }
937
938 if (!matching_entry) {
939 qdf_spin_unlock(&master_frame_list->lock);
940 mgmt_rx_reo_err("reo sim failure: absent in stale frame list");
941 qdf_assert_always(0);
942 }
943
944 status = qdf_list_remove_node(&master_frame_list->stale_list,
945 &matching_entry->node);
946
947 if (QDF_IS_STATUS_ERROR(status)) {
948 qdf_spin_unlock(&master_frame_list->lock);
949 return status;
950 }
951
952 qdf_mem_free(matching_entry);
953
954 qdf_spin_unlock(&master_frame_list->lock);
955
956 return QDF_STATUS_SUCCESS;
957 }
958
959 /**
960 * mgmt_rx_reo_handle_stale_frame() - API to handle stale management frames.
961 * @reo_list: Pointer to reorder list
962 * @desc: Pointer to frame descriptor
963 *
964 * Return: QDF_STATUS of operation
965 */
966 static QDF_STATUS
mgmt_rx_reo_handle_stale_frame(struct mgmt_rx_reo_list * reo_list,struct mgmt_rx_reo_frame_descriptor * desc)967 mgmt_rx_reo_handle_stale_frame(struct mgmt_rx_reo_list *reo_list,
968 struct mgmt_rx_reo_frame_descriptor *desc)
969 {
970 QDF_STATUS status;
971 struct mgmt_rx_reo_context *reo_context;
972 struct mgmt_rx_reo_sim_context *sim_context;
973 struct mgmt_rx_reo_params *reo_params;
974
975 if (!reo_list || !desc)
976 return QDF_STATUS_E_NULL_VALUE;
977
978 /* FW consumed/Error frames are already removed */
979 if (desc->type != MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME)
980 return QDF_STATUS_SUCCESS;
981
982 reo_context = mgmt_rx_reo_get_context_from_reo_list(reo_list);
983 if (!reo_context)
984 return QDF_STATUS_E_NULL_VALUE;
985
986 sim_context = &reo_context->sim_context;
987
988 reo_params = desc->rx_params->reo_params;
989 if (!reo_params)
990 return QDF_STATUS_E_NULL_VALUE;
991
992 status = mgmt_rx_reo_sim_remove_frame_from_stale_list(
993 &sim_context->master_frame_list, reo_params);
994
995 return status;
996 }
997 #endif /* WLAN_MGMT_RX_REO_SIM_SUPPORT */
998
999 /**
1000 * mgmt_rx_reo_is_potential_premature_delivery() - Helper API to check
1001 * whether the current frame getting delivered to upper layer is a premature
1002 * delivery
1003 * @release_reason: release reason
1004 *
1005 * Return: true for a premature delivery
1006 */
1007 static bool
mgmt_rx_reo_is_potential_premature_delivery(uint8_t release_reason)1008 mgmt_rx_reo_is_potential_premature_delivery(uint8_t release_reason)
1009 {
1010 return !(release_reason & RELEASE_REASON_ZERO_WAIT_COUNT);
1011 }
1012
1013 /**
1014 * wlan_mgmt_rx_reo_get_priv_object() - Get the pdev private object of
1015 * MGMT Rx REO module
1016 * @pdev: pointer to pdev object
1017 *
1018 * Return: Pointer to pdev private object of MGMT Rx REO module on success,
1019 * else NULL
1020 */
1021 static struct mgmt_rx_reo_pdev_info *
wlan_mgmt_rx_reo_get_priv_object(struct wlan_objmgr_pdev * pdev)1022 wlan_mgmt_rx_reo_get_priv_object(struct wlan_objmgr_pdev *pdev)
1023 {
1024 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
1025
1026 if (!pdev) {
1027 mgmt_rx_reo_err("pdev is null");
1028 return NULL;
1029 }
1030
1031 mgmt_txrx_pdev_ctx = (struct mgmt_txrx_priv_pdev_context *)
1032 wlan_objmgr_pdev_get_comp_private_obj(pdev,
1033 WLAN_UMAC_COMP_MGMT_TXRX);
1034
1035 if (!mgmt_txrx_pdev_ctx) {
1036 mgmt_rx_reo_err("mgmt txrx context is NULL");
1037 return NULL;
1038 }
1039
1040 return mgmt_txrx_pdev_ctx->mgmt_rx_reo_pdev_ctx;
1041 }
1042
1043 /**
1044 * mgmt_rx_reo_print_snapshots() - Print all snapshots related
1045 * to management Rx reorder module
1046 * @mac_hw_ss: MAC HW snapshot
1047 * @fw_forwarded_ss: FW forwarded snapshot
1048 * @fw_consumed_ss: FW consumed snapshot
1049 * @host_ss: Host snapshot
1050 *
1051 * return: QDF_STATUS
1052 */
1053 static QDF_STATUS
mgmt_rx_reo_print_snapshots(struct mgmt_rx_reo_snapshot_params * mac_hw_ss,struct mgmt_rx_reo_snapshot_params * fw_forwarded_ss,struct mgmt_rx_reo_snapshot_params * fw_consumed_ss,struct mgmt_rx_reo_snapshot_params * host_ss)1054 mgmt_rx_reo_print_snapshots
1055 (struct mgmt_rx_reo_snapshot_params *mac_hw_ss,
1056 struct mgmt_rx_reo_snapshot_params *fw_forwarded_ss,
1057 struct mgmt_rx_reo_snapshot_params *fw_consumed_ss,
1058 struct mgmt_rx_reo_snapshot_params *host_ss)
1059 {
1060 mgmt_rx_reo_debug("HW SS: valid = %u, ctr = %u, ts = %u",
1061 mac_hw_ss->valid, mac_hw_ss->mgmt_pkt_ctr,
1062 mac_hw_ss->global_timestamp);
1063 mgmt_rx_reo_debug("FW forwarded SS: valid = %u, ctr = %u, ts = %u",
1064 fw_forwarded_ss->valid,
1065 fw_forwarded_ss->mgmt_pkt_ctr,
1066 fw_forwarded_ss->global_timestamp);
1067 mgmt_rx_reo_debug("FW consumed SS: valid = %u, ctr = %u, ts = %u",
1068 fw_consumed_ss->valid,
1069 fw_consumed_ss->mgmt_pkt_ctr,
1070 fw_consumed_ss->global_timestamp);
1071 mgmt_rx_reo_debug("HOST SS: valid = %u, ctr = %u, ts = %u",
1072 host_ss->valid, host_ss->mgmt_pkt_ctr,
1073 host_ss->global_timestamp);
1074
1075 return QDF_STATUS_SUCCESS;
1076 }
1077
1078 /**
1079 * mgmt_rx_reo_invalidate_stale_snapshots() - Invalidate stale management
1080 * Rx REO snapshots
1081 * @mac_hw_ss: MAC HW snapshot
1082 * @fw_forwarded_ss: FW forwarded snapshot
1083 * @fw_consumed_ss: FW consumed snapshot
1084 * @host_ss: Host snapshot
1085 * @link: link ID
1086 *
1087 * return: QDF_STATUS
1088 */
1089 static QDF_STATUS
mgmt_rx_reo_invalidate_stale_snapshots(struct mgmt_rx_reo_snapshot_params * mac_hw_ss,struct mgmt_rx_reo_snapshot_params * fw_forwarded_ss,struct mgmt_rx_reo_snapshot_params * fw_consumed_ss,struct mgmt_rx_reo_snapshot_params * host_ss,uint8_t link)1090 mgmt_rx_reo_invalidate_stale_snapshots
1091 (struct mgmt_rx_reo_snapshot_params *mac_hw_ss,
1092 struct mgmt_rx_reo_snapshot_params *fw_forwarded_ss,
1093 struct mgmt_rx_reo_snapshot_params *fw_consumed_ss,
1094 struct mgmt_rx_reo_snapshot_params *host_ss,
1095 uint8_t link)
1096 {
1097 if (!mac_hw_ss->valid)
1098 return QDF_STATUS_SUCCESS;
1099
1100 if (host_ss->valid) {
1101 if (!mgmt_rx_reo_compare_global_timestamps_gte
1102 (mac_hw_ss->global_timestamp,
1103 host_ss->global_timestamp) ||
1104 !mgmt_rx_reo_compare_pkt_ctrs_gte
1105 (mac_hw_ss->mgmt_pkt_ctr,
1106 host_ss->mgmt_pkt_ctr)) {
1107 mgmt_rx_reo_print_snapshots(mac_hw_ss, fw_forwarded_ss,
1108 fw_consumed_ss, host_ss);
1109 mgmt_rx_reo_debug("Invalidate host snapshot, link %u",
1110 link);
1111 host_ss->valid = false;
1112 }
1113 }
1114
1115 if (fw_forwarded_ss->valid) {
1116 if (!mgmt_rx_reo_compare_global_timestamps_gte
1117 (mac_hw_ss->global_timestamp,
1118 fw_forwarded_ss->global_timestamp) ||
1119 !mgmt_rx_reo_compare_pkt_ctrs_gte
1120 (mac_hw_ss->mgmt_pkt_ctr,
1121 fw_forwarded_ss->mgmt_pkt_ctr)) {
1122 mgmt_rx_reo_print_snapshots(mac_hw_ss, fw_forwarded_ss,
1123 fw_consumed_ss, host_ss);
1124 mgmt_rx_reo_debug("Invalidate FW forwarded SS, link %u",
1125 link);
1126 fw_forwarded_ss->valid = false;
1127 }
1128
1129 if (host_ss->valid && fw_forwarded_ss->valid &&
1130 (mgmt_rx_reo_compare_global_timestamps_gte
1131 (host_ss->global_timestamp,
1132 fw_forwarded_ss->global_timestamp) !=
1133 mgmt_rx_reo_compare_pkt_ctrs_gte
1134 (host_ss->mgmt_pkt_ctr,
1135 fw_forwarded_ss->mgmt_pkt_ctr))) {
1136 mgmt_rx_reo_print_snapshots(mac_hw_ss, fw_forwarded_ss,
1137 fw_consumed_ss, host_ss);
1138 mgmt_rx_reo_debug("Invalidate FW forwarded SS, link %u",
1139 link);
1140 fw_forwarded_ss->valid = false;
1141 }
1142 }
1143
1144 if (fw_consumed_ss->valid) {
1145 if (!mgmt_rx_reo_compare_global_timestamps_gte
1146 (mac_hw_ss->global_timestamp,
1147 fw_consumed_ss->global_timestamp) ||
1148 !mgmt_rx_reo_compare_pkt_ctrs_gte
1149 (mac_hw_ss->mgmt_pkt_ctr,
1150 fw_consumed_ss->mgmt_pkt_ctr)) {
1151 mgmt_rx_reo_print_snapshots(mac_hw_ss, fw_forwarded_ss,
1152 fw_consumed_ss, host_ss);
1153 mgmt_rx_reo_debug("Invalidate FW consumed SS, link %u",
1154 link);
1155 fw_consumed_ss->valid = false;
1156 }
1157
1158 if (host_ss->valid && fw_consumed_ss->valid &&
1159 (mgmt_rx_reo_compare_global_timestamps_gte
1160 (host_ss->global_timestamp,
1161 fw_consumed_ss->global_timestamp) !=
1162 mgmt_rx_reo_compare_pkt_ctrs_gte
1163 (host_ss->mgmt_pkt_ctr,
1164 fw_consumed_ss->mgmt_pkt_ctr))) {
1165 mgmt_rx_reo_print_snapshots(mac_hw_ss, fw_forwarded_ss,
1166 fw_consumed_ss, host_ss);
1167 mgmt_rx_reo_debug("Invalidate FW consumed SS, link %u",
1168 link);
1169 fw_consumed_ss->valid = false;
1170 }
1171 }
1172
1173 return QDF_STATUS_SUCCESS;
1174 }
1175
1176 /**
1177 * mgmt_rx_reo_snapshots_check_sanity() - Check the sanity of management
1178 * Rx REO snapshots
1179 * @mac_hw_ss: MAC HW snapshot
1180 * @fw_forwarded_ss: FW forwarded snapshot
1181 * @fw_consumed_ss: FW consumed snapshot
1182 * @host_ss: Host snapshot
1183 *
1184 * return: QDF_STATUS
1185 */
1186 static QDF_STATUS
mgmt_rx_reo_snapshots_check_sanity(struct mgmt_rx_reo_snapshot_params * mac_hw_ss,struct mgmt_rx_reo_snapshot_params * fw_forwarded_ss,struct mgmt_rx_reo_snapshot_params * fw_consumed_ss,struct mgmt_rx_reo_snapshot_params * host_ss)1187 mgmt_rx_reo_snapshots_check_sanity
1188 (struct mgmt_rx_reo_snapshot_params *mac_hw_ss,
1189 struct mgmt_rx_reo_snapshot_params *fw_forwarded_ss,
1190 struct mgmt_rx_reo_snapshot_params *fw_consumed_ss,
1191 struct mgmt_rx_reo_snapshot_params *host_ss)
1192 {
1193 QDF_STATUS status;
1194
1195 if (!mac_hw_ss->valid) {
1196 if (fw_forwarded_ss->valid || fw_consumed_ss->valid ||
1197 host_ss->valid) {
1198 mgmt_rx_reo_warn_rl("MAC HW SS is invalid");
1199 status = QDF_STATUS_E_INVAL;
1200 goto fail;
1201 }
1202
1203 return QDF_STATUS_SUCCESS;
1204 }
1205
1206 if (!fw_forwarded_ss->valid && !fw_consumed_ss->valid) {
1207 if (host_ss->valid) {
1208 mgmt_rx_reo_warn_rl("FW fwd and consumed SS invalid");
1209 status = QDF_STATUS_E_INVAL;
1210 goto fail;
1211 }
1212
1213 return QDF_STATUS_SUCCESS;
1214 }
1215
1216 if (fw_forwarded_ss->valid) {
1217 if (!mgmt_rx_reo_compare_global_timestamps_gte
1218 (mac_hw_ss->global_timestamp,
1219 fw_forwarded_ss->global_timestamp)) {
1220 mgmt_rx_reo_warn_rl("TS: MAC HW SS < FW forwarded SS");
1221 status = QDF_STATUS_E_INVAL;
1222 goto fail;
1223 }
1224
1225 if (!mgmt_rx_reo_compare_pkt_ctrs_gte
1226 (mac_hw_ss->mgmt_pkt_ctr,
1227 fw_forwarded_ss->mgmt_pkt_ctr)) {
1228 mgmt_rx_reo_warn_rl("CTR: MAC HW SS < FW forwarded SS");
1229 status = QDF_STATUS_E_INVAL;
1230 goto fail;
1231 }
1232 }
1233
1234 if (fw_consumed_ss->valid) {
1235 if (!mgmt_rx_reo_compare_global_timestamps_gte
1236 (mac_hw_ss->global_timestamp,
1237 fw_consumed_ss->global_timestamp)) {
1238 mgmt_rx_reo_warn_rl("TS: MAC HW SS < FW consumed SS");
1239 status = QDF_STATUS_E_INVAL;
1240 goto fail;
1241 }
1242
1243 if (!mgmt_rx_reo_compare_pkt_ctrs_gte
1244 (mac_hw_ss->mgmt_pkt_ctr,
1245 fw_consumed_ss->mgmt_pkt_ctr)) {
1246 mgmt_rx_reo_warn_rl("CTR: MAC HW SS < FW consumed SS");
1247 status = QDF_STATUS_E_INVAL;
1248 goto fail;
1249 }
1250 }
1251
1252 if (host_ss->valid) {
1253 if (!mgmt_rx_reo_compare_global_timestamps_gte
1254 (mac_hw_ss->global_timestamp,
1255 host_ss->global_timestamp)) {
1256 mgmt_rx_reo_warn_rl("TS: MAC HW SS < host SS");
1257 status = QDF_STATUS_E_INVAL;
1258 goto fail;
1259 }
1260
1261 if (!mgmt_rx_reo_compare_pkt_ctrs_gte
1262 (mac_hw_ss->mgmt_pkt_ctr,
1263 host_ss->mgmt_pkt_ctr)) {
1264 mgmt_rx_reo_warn_rl("PKT CTR: MAC HW SS < host SS");
1265 status = QDF_STATUS_E_INVAL;
1266 goto fail;
1267 }
1268
1269 if (fw_forwarded_ss->valid && !fw_consumed_ss->valid) {
1270 if (!mgmt_rx_reo_compare_global_timestamps_gte
1271 (fw_forwarded_ss->global_timestamp,
1272 host_ss->global_timestamp)) {
1273 mgmt_rx_reo_warn_rl("TS: FW fwd < host SS");
1274 status = QDF_STATUS_E_INVAL;
1275 goto fail;
1276 }
1277
1278 if (!mgmt_rx_reo_compare_pkt_ctrs_gte
1279 (fw_forwarded_ss->mgmt_pkt_ctr,
1280 host_ss->mgmt_pkt_ctr)) {
1281 mgmt_rx_reo_warn_rl("CTR: FW fwd < host SS");
1282 status = QDF_STATUS_E_INVAL;
1283 goto fail;
1284 }
1285 }
1286
1287 if (fw_consumed_ss->valid && !fw_forwarded_ss->valid) {
1288 if (!mgmt_rx_reo_compare_global_timestamps_gte
1289 (fw_consumed_ss->global_timestamp,
1290 host_ss->global_timestamp)) {
1291 mgmt_rx_reo_warn_rl("TS: FW consumed < host");
1292 status = QDF_STATUS_E_INVAL;
1293 goto fail;
1294 }
1295
1296 if (!mgmt_rx_reo_compare_pkt_ctrs_gte
1297 (fw_consumed_ss->mgmt_pkt_ctr,
1298 host_ss->mgmt_pkt_ctr)) {
1299 mgmt_rx_reo_warn_rl("CTR: FW consumed < host");
1300 status = QDF_STATUS_E_INVAL;
1301 goto fail;
1302 }
1303 }
1304
1305 if (fw_forwarded_ss->valid && fw_consumed_ss->valid) {
1306 if (!mgmt_rx_reo_compare_global_timestamps_gte
1307 (fw_consumed_ss->global_timestamp,
1308 host_ss->global_timestamp) &&
1309 !mgmt_rx_reo_compare_global_timestamps_gte
1310 (fw_forwarded_ss->global_timestamp,
1311 host_ss->global_timestamp)) {
1312 mgmt_rx_reo_warn_rl("TS: FW consumed/fwd<host");
1313 status = QDF_STATUS_E_INVAL;
1314 goto fail;
1315 }
1316
1317 if (!mgmt_rx_reo_compare_pkt_ctrs_gte
1318 (fw_consumed_ss->mgmt_pkt_ctr,
1319 host_ss->mgmt_pkt_ctr) &&
1320 !mgmt_rx_reo_compare_pkt_ctrs_gte
1321 (fw_forwarded_ss->mgmt_pkt_ctr,
1322 host_ss->mgmt_pkt_ctr)) {
1323 mgmt_rx_reo_warn_rl("CTR:FW consumed/fwd<host");
1324 status = QDF_STATUS_E_INVAL;
1325 goto fail;
1326 }
1327 }
1328 }
1329
1330 return QDF_STATUS_SUCCESS;
1331
1332 fail:
1333 mgmt_rx_reo_warn_rl("HW SS: valid = %u, ctr = %u, ts = %u",
1334 mac_hw_ss->valid, mac_hw_ss->mgmt_pkt_ctr,
1335 mac_hw_ss->global_timestamp);
1336 mgmt_rx_reo_warn_rl("FW forwarded SS: valid = %u, ctr = %u, ts = %u",
1337 fw_forwarded_ss->valid,
1338 fw_forwarded_ss->mgmt_pkt_ctr,
1339 fw_forwarded_ss->global_timestamp);
1340 mgmt_rx_reo_warn_rl("FW consumed SS: valid = %u, ctr = %u, ts = %u",
1341 fw_consumed_ss->valid,
1342 fw_consumed_ss->mgmt_pkt_ctr,
1343 fw_consumed_ss->global_timestamp);
1344 mgmt_rx_reo_warn_rl("HOST SS: valid = %u, ctr = %u, ts = %u",
1345 host_ss->valid, host_ss->mgmt_pkt_ctr,
1346 host_ss->global_timestamp);
1347
1348 return status;
1349 }
1350
1351 /**
1352 * wlan_mgmt_rx_reo_algo_calculate_wait_count() - Calculates the number of
1353 * frames an incoming frame should wait for before it gets delivered.
1354 * @in_frame_pdev: pdev on which this frame is received
1355 * @desc: frame Descriptor
1356 *
1357 * Each frame carrys a MGMT pkt number which is local to that link, and a
1358 * timestamp which is global across all the links. MAC HW and FW also captures
1359 * the same details of the last frame that they have seen. Host also maintains
1360 * the details of the last frame it has seen. In total, there are 4 snapshots.
1361 * 1. MAC HW snapshot - latest frame seen at MAC HW
1362 * 2. FW forwarded snapshot- latest frame forwarded to the Host
1363 * 3. FW consumed snapshot - latest frame consumed by the FW
1364 * 4. Host/FW consumed snapshot - latest frame seen by the Host
1365 * By using all these snapshots, this function tries to compute the wait count
1366 * for a given incoming frame on all links.
1367 *
1368 * Return: QDF_STATUS of operation
1369 */
1370 static QDF_STATUS
wlan_mgmt_rx_reo_algo_calculate_wait_count(struct wlan_objmgr_pdev * in_frame_pdev,struct mgmt_rx_reo_frame_descriptor * desc)1371 wlan_mgmt_rx_reo_algo_calculate_wait_count(
1372 struct wlan_objmgr_pdev *in_frame_pdev,
1373 struct mgmt_rx_reo_frame_descriptor *desc)
1374 {
1375 QDF_STATUS status;
1376 uint8_t link;
1377 int8_t grp_id;
1378 int8_t in_frame_link;
1379 int frames_pending, delta_fwd_host;
1380 uint8_t snapshot_id;
1381 struct wlan_objmgr_pdev *pdev;
1382 struct mgmt_rx_reo_pdev_info *rx_reo_pdev_ctx;
1383 struct mgmt_rx_reo_pdev_info *in_frame_rx_reo_pdev_ctx;
1384 struct mgmt_rx_reo_snapshot_info *snapshot_info;
1385 struct mgmt_rx_reo_snapshot_params snapshot_params
1386 [MGMT_RX_REO_SHARED_SNAPSHOT_MAX];
1387 struct mgmt_rx_reo_snapshot_params *mac_hw_ss, *fw_forwarded_ss,
1388 *fw_consumed_ss, *host_ss;
1389 struct mgmt_rx_reo_params *in_frame_params;
1390 struct mgmt_rx_reo_wait_count *wait_count;
1391
1392 if (!in_frame_pdev) {
1393 mgmt_rx_reo_err("pdev is null");
1394 return QDF_STATUS_E_NULL_VALUE;
1395 }
1396
1397 if (!desc) {
1398 mgmt_rx_reo_err("Frame descriptor is null");
1399 return QDF_STATUS_E_NULL_VALUE;
1400 }
1401
1402 if (!desc->rx_params) {
1403 mgmt_rx_reo_err("MGMT Rx params of incoming frame is NULL");
1404 return QDF_STATUS_E_NULL_VALUE;
1405 }
1406
1407 in_frame_params = desc->rx_params->reo_params;
1408 if (!in_frame_params) {
1409 mgmt_rx_reo_err("MGMT Rx REO params of incoming frame is NULL");
1410 return QDF_STATUS_E_NULL_VALUE;
1411 }
1412
1413 wait_count = &desc->wait_count;
1414
1415 /* Get the MLO link ID of incoming frame */
1416 in_frame_link = wlan_get_mlo_link_id_from_pdev(in_frame_pdev);
1417 grp_id = wlan_get_mlo_grp_id_from_pdev(in_frame_pdev);
1418 if (in_frame_link < 0 || in_frame_link >= MAX_MLO_LINKS) {
1419 mgmt_rx_reo_err("Invalid frame link = %d", in_frame_link);
1420 return QDF_STATUS_E_INVAL;
1421 }
1422
1423 if (!mgmt_rx_reo_is_valid_link(in_frame_link, grp_id)) {
1424 mgmt_rx_reo_err("Invalid link = %d and group = %d",
1425 in_frame_link, grp_id);
1426 return QDF_STATUS_E_INVAL;
1427 }
1428
1429 in_frame_rx_reo_pdev_ctx =
1430 wlan_mgmt_rx_reo_get_priv_object(in_frame_pdev);
1431 if (!in_frame_rx_reo_pdev_ctx) {
1432 mgmt_rx_reo_err("Reo context null for incoming frame pdev");
1433 return QDF_STATUS_E_FAILURE;
1434 }
1435 qdf_mem_zero(in_frame_rx_reo_pdev_ctx->raw_snapshots,
1436 sizeof(in_frame_rx_reo_pdev_ctx->raw_snapshots));
1437
1438 /* Iterate over all the valid MLO links */
1439 for (link = 0; link < MAX_MLO_LINKS; link++) {
1440 /* No need wait for any frames on an invalid link */
1441 if (!mgmt_rx_reo_is_valid_link(link, grp_id)) {
1442 frames_pending = 0;
1443 goto update_pending_frames;
1444 }
1445
1446 pdev = wlan_get_pdev_from_mlo_link_id(link, grp_id,
1447 WLAN_MGMT_RX_REO_ID);
1448
1449 /* No need to wait for any frames if the pdev is not found */
1450 if (!pdev) {
1451 mgmt_rx_reo_debug("pdev is null for link %d", link);
1452 frames_pending = 0;
1453 goto update_pending_frames;
1454 }
1455
1456 rx_reo_pdev_ctx = wlan_mgmt_rx_reo_get_priv_object(pdev);
1457 if (!rx_reo_pdev_ctx) {
1458 mgmt_rx_reo_err("Mgmt reo context empty for pdev %pK",
1459 pdev);
1460 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
1461 return QDF_STATUS_E_FAILURE;
1462 }
1463
1464 if (!rx_reo_pdev_ctx->init_complete) {
1465 mgmt_rx_reo_debug("REO init in progress for link %d",
1466 link);
1467 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
1468 frames_pending = 0;
1469 goto update_pending_frames;
1470 }
1471
1472 host_ss = &rx_reo_pdev_ctx->host_snapshot;
1473 desc->host_snapshot[link] = rx_reo_pdev_ctx->host_snapshot;
1474
1475 mgmt_rx_reo_info("link_id = %u HOST SS: valid = %u, ctr = %u, ts = %u",
1476 link, host_ss->valid, host_ss->mgmt_pkt_ctr,
1477 host_ss->global_timestamp);
1478
1479 snapshot_id = 0;
1480 /* Read all the shared snapshots */
1481 while (snapshot_id <
1482 MGMT_RX_REO_SHARED_SNAPSHOT_MAX) {
1483 snapshot_info = &rx_reo_pdev_ctx->
1484 host_target_shared_snapshot_info[snapshot_id];
1485
1486 qdf_mem_zero(&snapshot_params[snapshot_id],
1487 sizeof(snapshot_params[snapshot_id]));
1488
1489 status = tgt_mgmt_rx_reo_read_snapshot(
1490 pdev, snapshot_info, snapshot_id,
1491 &snapshot_params[snapshot_id],
1492 in_frame_rx_reo_pdev_ctx->raw_snapshots
1493 [link][snapshot_id]);
1494
1495 /* Read operation shouldn't fail */
1496 if (QDF_IS_STATUS_ERROR(status)) {
1497 mgmt_rx_reo_err("snapshot(%d) read failed on"
1498 "link (%d)", snapshot_id, link);
1499 wlan_objmgr_pdev_release_ref(
1500 pdev, WLAN_MGMT_RX_REO_ID);
1501 return status;
1502 }
1503
1504 /* If snapshot is valid, save it in the pdev context */
1505 if (snapshot_params[snapshot_id].valid) {
1506 rx_reo_pdev_ctx->
1507 last_valid_shared_snapshot[snapshot_id] =
1508 snapshot_params[snapshot_id];
1509 }
1510 desc->shared_snapshots[link][snapshot_id] =
1511 snapshot_params[snapshot_id];
1512
1513 snapshot_id++;
1514 }
1515
1516 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
1517
1518 mac_hw_ss = &snapshot_params
1519 [MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW];
1520 fw_forwarded_ss = &snapshot_params
1521 [MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED];
1522 fw_consumed_ss = &snapshot_params
1523 [MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED];
1524
1525 status = mgmt_rx_reo_invalidate_stale_snapshots(mac_hw_ss,
1526 fw_forwarded_ss,
1527 fw_consumed_ss,
1528 host_ss, link);
1529 if (QDF_IS_STATUS_ERROR(status)) {
1530 mgmt_rx_reo_err("Failed to invalidate SS for link %u",
1531 link);
1532 return status;
1533 }
1534
1535 desc->shared_snapshots[link][MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW] =
1536 *mac_hw_ss;
1537 desc->shared_snapshots[link][MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED] =
1538 *fw_forwarded_ss;
1539 desc->shared_snapshots[link][MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED] =
1540 *fw_consumed_ss;
1541 desc->host_snapshot[link] = *host_ss;
1542
1543 status = mgmt_rx_reo_snapshots_check_sanity
1544 (mac_hw_ss, fw_forwarded_ss, fw_consumed_ss, host_ss);
1545 if (QDF_IS_STATUS_ERROR(status)) {
1546 QDF_STATUS ret;
1547
1548 ret = handle_snapshot_sanity_failures(desc, link);
1549 if (QDF_IS_STATUS_ERROR(ret)) {
1550 mgmt_rx_reo_err_rl("Err:SS sanity fail handle");
1551 return ret;
1552 }
1553 mgmt_rx_reo_warn_rl("Drop frame due to SS sanity fail");
1554
1555 return status;
1556 }
1557
1558 mgmt_rx_reo_info("link_id = %u HW SS: valid = %u, ctr = %u, ts = %u",
1559 link, mac_hw_ss->valid,
1560 mac_hw_ss->mgmt_pkt_ctr,
1561 mac_hw_ss->global_timestamp);
1562 mgmt_rx_reo_info("link_id = %u FW forwarded SS: valid = %u, ctr = %u, ts = %u",
1563 link, fw_forwarded_ss->valid,
1564 fw_forwarded_ss->mgmt_pkt_ctr,
1565 fw_forwarded_ss->global_timestamp);
1566 mgmt_rx_reo_info("link_id = %u FW consumed SS: valid = %u, ctr = %u, ts = %u",
1567 link, fw_consumed_ss->valid,
1568 fw_consumed_ss->mgmt_pkt_ctr,
1569 fw_consumed_ss->global_timestamp);
1570
1571 /* No need wait for any frames on the same link */
1572 if (link == in_frame_link) {
1573 frames_pending = 0;
1574 goto update_pending_frames;
1575 }
1576
1577 /**
1578 * If MAC HW snapshot is invalid, the link has not started
1579 * receiving management frames. Set wait count to zero.
1580 */
1581 if (!mac_hw_ss->valid) {
1582 frames_pending = 0;
1583 goto update_pending_frames;
1584 }
1585
1586 /**
1587 * If host snapshot is invalid, wait for MAX number of frames.
1588 * When any frame in this link arrives at host, actual wait
1589 * counts will be updated.
1590 */
1591 if (!host_ss->valid) {
1592 wait_count->per_link_count[link] = UINT_MAX;
1593 wait_count->total_count += UINT_MAX;
1594 goto print_wait_count;
1595 }
1596
1597 /**
1598 * If MAC HW snapshot sequence number and host snapshot
1599 * sequence number are same, all the frames received by
1600 * this link are processed by host. No need to wait for
1601 * any frames from this link.
1602 */
1603 if (!mgmt_rx_reo_subtract_pkt_ctrs(mac_hw_ss->mgmt_pkt_ctr,
1604 host_ss->mgmt_pkt_ctr)) {
1605 frames_pending = 0;
1606 goto update_pending_frames;
1607 }
1608
1609 /**
1610 * Ideally, the incoming frame has to wait for only those frames
1611 * (on other links) which meet all the below criterion.
1612 * 1. Frame's timestamp is less than incoming frame's
1613 * 2. Frame is supposed to be consumed by the Host
1614 * 3. Frame is not yet seen by the Host.
1615 * We may not be able to compute the exact optimal wait count
1616 * because HW/FW provides a limited assist.
1617 * This algorithm tries to get the best estimate of wait count
1618 * by not waiting for those frames where we have a conclusive
1619 * evidence that we don't have to wait for those frames.
1620 */
1621
1622 /**
1623 * If this link has already seen a frame whose timestamp is
1624 * greater than or equal to incoming frame's timestamp,
1625 * then no need to wait for any frames on this link.
1626 * If the total wait count becomes zero, then the policy on
1627 * whether to deliver such a frame to upper layers is handled
1628 * separately.
1629 */
1630 if (mgmt_rx_reo_compare_global_timestamps_gte(
1631 host_ss->global_timestamp,
1632 in_frame_params->global_timestamp)) {
1633 frames_pending = 0;
1634 goto update_pending_frames;
1635 }
1636
1637 /**
1638 * For starters, we only have to wait for the frames that are
1639 * seen by MAC HW but not yet seen by Host. The frames which
1640 * reach MAC HW later are guaranteed to have a timestamp
1641 * greater than incoming frame's timestamp.
1642 */
1643 frames_pending = mgmt_rx_reo_subtract_pkt_ctrs(
1644 mac_hw_ss->mgmt_pkt_ctr,
1645 host_ss->mgmt_pkt_ctr);
1646 qdf_assert_always(frames_pending >= 0);
1647
1648 if (frames_pending &&
1649 mgmt_rx_reo_compare_global_timestamps_gte
1650 (mac_hw_ss->global_timestamp,
1651 in_frame_params->global_timestamp)) {
1652 /**
1653 * Last frame seen at MAC HW has timestamp greater than
1654 * or equal to incoming frame's timestamp. So no need to
1655 * wait for that last frame, but we can't conclusively
1656 * say anything about timestamp of frames before the
1657 * last frame, so try to wait for all of those frames.
1658 */
1659 frames_pending--;
1660 qdf_assert_always(frames_pending >= 0);
1661
1662 if (fw_consumed_ss->valid &&
1663 mgmt_rx_reo_compare_global_timestamps_gte(
1664 fw_consumed_ss->global_timestamp,
1665 in_frame_params->global_timestamp)) {
1666 /**
1667 * Last frame consumed by the FW has timestamp
1668 * greater than or equal to incoming frame's.
1669 * That means all the frames from
1670 * fw_consumed_ss->mgmt_pkt_ctr to
1671 * mac_hw->mgmt_pkt_ctr will have timestamp
1672 * greater than or equal to incoming frame's and
1673 * hence, no need to wait for those frames.
1674 * We just need to wait for frames from
1675 * host_ss->mgmt_pkt_ctr to
1676 * fw_consumed_ss->mgmt_pkt_ctr-1. This is a
1677 * better estimate over the above estimate,
1678 * so update frames_pending.
1679 */
1680 frames_pending =
1681 mgmt_rx_reo_subtract_pkt_ctrs(
1682 fw_consumed_ss->mgmt_pkt_ctr,
1683 host_ss->mgmt_pkt_ctr) - 1;
1684
1685 qdf_assert_always(frames_pending >= 0);
1686
1687 /**
1688 * Last frame forwarded to Host has timestamp
1689 * less than incoming frame's. That means all
1690 * the frames starting from
1691 * fw_forwarded_ss->mgmt_pkt_ctr+1 to
1692 * fw_consumed_ss->mgmt_pkt_ctr are consumed by
1693 * the FW and hence, no need to wait for those
1694 * frames. We just need to wait for frames
1695 * from host_ss->mgmt_pkt_ctr to
1696 * fw_forwarded_ss->mgmt_pkt_ctr. This is a
1697 * better estimate over the above estimate,
1698 * so update frames_pending.
1699 */
1700 if (fw_forwarded_ss->valid &&
1701 !mgmt_rx_reo_compare_global_timestamps_gte(
1702 fw_forwarded_ss->global_timestamp,
1703 in_frame_params->global_timestamp)) {
1704 frames_pending =
1705 mgmt_rx_reo_subtract_pkt_ctrs(
1706 fw_forwarded_ss->mgmt_pkt_ctr,
1707 host_ss->mgmt_pkt_ctr);
1708
1709 /**
1710 * frames_pending can be negative in
1711 * cases whene there are no frames
1712 * getting forwarded to the Host. No
1713 * need to wait for any frames in that
1714 * case.
1715 */
1716 if (frames_pending < 0)
1717 frames_pending = 0;
1718 }
1719 }
1720
1721 /**
1722 * Last frame forwarded to Host has timestamp greater
1723 * than or equal to incoming frame's. That means all the
1724 * frames from fw_forwarded->mgmt_pkt_ctr to
1725 * mac_hw->mgmt_pkt_ctr will have timestamp greater than
1726 * or equal to incoming frame's and hence, no need to
1727 * wait for those frames. We may have to just wait for
1728 * frames from host_ss->mgmt_pkt_ctr to
1729 * fw_forwarded_ss->mgmt_pkt_ctr-1
1730 */
1731 if (fw_forwarded_ss->valid &&
1732 mgmt_rx_reo_compare_global_timestamps_gte(
1733 fw_forwarded_ss->global_timestamp,
1734 in_frame_params->global_timestamp)) {
1735 delta_fwd_host =
1736 mgmt_rx_reo_subtract_pkt_ctrs(
1737 fw_forwarded_ss->mgmt_pkt_ctr,
1738 host_ss->mgmt_pkt_ctr) - 1;
1739
1740 qdf_assert_always(delta_fwd_host >= 0);
1741
1742 /**
1743 * This will be a better estimate over the one
1744 * we computed using mac_hw_ss but this may or
1745 * may not be a better estimate over the
1746 * one we computed using fw_consumed_ss.
1747 * When timestamps of both fw_consumed_ss and
1748 * fw_forwarded_ss are greater than incoming
1749 * frame's but timestamp of fw_consumed_ss is
1750 * smaller than fw_forwarded_ss, then
1751 * frames_pending will be smaller than
1752 * delta_fwd_host, the reverse will be true in
1753 * other cases. Instead of checking for all
1754 * those cases, just waiting for the minimum
1755 * among these two should be sufficient.
1756 */
1757 frames_pending = qdf_min(frames_pending,
1758 delta_fwd_host);
1759 qdf_assert_always(frames_pending >= 0);
1760 }
1761 }
1762
1763 update_pending_frames:
1764 qdf_assert_always(frames_pending >= 0);
1765
1766 wait_count->per_link_count[link] = frames_pending;
1767 wait_count->total_count += frames_pending;
1768
1769 print_wait_count:
1770 mgmt_rx_reo_info("link_id = %u wait count: per link = 0x%x, total = 0x%llx",
1771 link, wait_count->per_link_count[link],
1772 wait_count->total_count);
1773 }
1774
1775 return QDF_STATUS_SUCCESS;
1776 }
1777
1778 /**
1779 * struct mgmt_rx_reo_list_entry_debug_info - This structure holds the necessary
1780 * information about a reo list entry for debug purposes.
1781 * @link_id: link id
1782 * @mgmt_pkt_ctr: management packet counter
1783 * @global_timestamp: global time stamp
1784 * @wait_count: wait count values
1785 * @status: status of the entry in the list
1786 * @entry: pointer to reo list entry
1787 */
1788 struct mgmt_rx_reo_list_entry_debug_info {
1789 uint8_t link_id;
1790 uint16_t mgmt_pkt_ctr;
1791 uint32_t global_timestamp;
1792 struct mgmt_rx_reo_wait_count wait_count;
1793 uint32_t status;
1794 struct mgmt_rx_reo_list_entry *entry;
1795 };
1796
1797 /**
1798 * mgmt_rx_reo_list_display() - API to print the entries in the reorder list
1799 * @reo_list: Pointer to reorder list
1800 *
1801 * Return: QDF_STATUS
1802 */
1803 static QDF_STATUS
mgmt_rx_reo_list_display(struct mgmt_rx_reo_list * reo_list)1804 mgmt_rx_reo_list_display(struct mgmt_rx_reo_list *reo_list)
1805 {
1806 uint32_t reo_list_size;
1807 uint32_t index;
1808 struct mgmt_rx_reo_list_entry *cur_entry;
1809 struct mgmt_rx_reo_list_entry_debug_info *debug_info;
1810
1811 if (!reo_list) {
1812 mgmt_rx_reo_err("Pointer to reo list is null");
1813 return QDF_STATUS_E_NULL_VALUE;
1814 }
1815
1816 qdf_spin_lock_bh(&reo_list->list_lock);
1817
1818 reo_list_size = qdf_list_size(&reo_list->list);
1819
1820 if (reo_list_size == 0) {
1821 qdf_spin_unlock_bh(&reo_list->list_lock);
1822 mgmt_rx_reo_debug("Number of entries in the reo list = %u",
1823 reo_list_size);
1824 return QDF_STATUS_SUCCESS;
1825 }
1826
1827 debug_info = qdf_mem_malloc_atomic(reo_list_size * sizeof(*debug_info));
1828 if (!debug_info) {
1829 qdf_spin_unlock_bh(&reo_list->list_lock);
1830 mgmt_rx_reo_err("Memory allocation failed");
1831 return QDF_STATUS_E_NOMEM;
1832 }
1833
1834 index = 0;
1835 qdf_list_for_each(&reo_list->list, cur_entry, node) {
1836 debug_info[index].link_id =
1837 mgmt_rx_reo_get_link_id(cur_entry->rx_params);
1838 debug_info[index].mgmt_pkt_ctr =
1839 mgmt_rx_reo_get_pkt_counter(cur_entry->rx_params);
1840 debug_info[index].global_timestamp =
1841 mgmt_rx_reo_get_global_ts(cur_entry->rx_params);
1842 debug_info[index].wait_count = cur_entry->wait_count;
1843 debug_info[index].status = cur_entry->status;
1844 debug_info[index].entry = cur_entry;
1845
1846 ++index;
1847 }
1848
1849 qdf_spin_unlock_bh(&reo_list->list_lock);
1850
1851 mgmt_rx_reo_debug("Reorder list");
1852 mgmt_rx_reo_debug("##################################################");
1853 mgmt_rx_reo_debug("Number of entries in the reo list = %u",
1854 reo_list_size);
1855 for (index = 0; index < reo_list_size; index++) {
1856 uint8_t link_id;
1857
1858 mgmt_rx_reo_debug("index = %u: link_id = %u, ts = %u, ctr = %u, status = 0x%x, entry = %pK",
1859 index, debug_info[index].link_id,
1860 debug_info[index].global_timestamp,
1861 debug_info[index].mgmt_pkt_ctr,
1862 debug_info[index].status,
1863 debug_info[index].entry);
1864
1865 mgmt_rx_reo_debug("Total wait count = 0x%llx",
1866 debug_info[index].wait_count.total_count);
1867
1868 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++)
1869 mgmt_rx_reo_debug("Link id = %u, wait_count = 0x%x",
1870 link_id, debug_info[index].wait_count.
1871 per_link_count[link_id]);
1872 }
1873 mgmt_rx_reo_debug("##################################################");
1874
1875 qdf_mem_free(debug_info);
1876
1877 return QDF_STATUS_SUCCESS;
1878 }
1879
1880 #ifdef WLAN_MGMT_RX_REO_DEBUG_SUPPORT
1881 /**
1882 * mgmt_rx_reo_egress_frame_debug_info_enabled() - API to check whether egress
1883 * frame info debug feaure is enabled
1884 * @egress_frame_debug_info: Pointer to egress frame debug info object
1885 *
1886 * Return: true or false
1887 */
1888 static bool
mgmt_rx_reo_egress_frame_debug_info_enabled(struct reo_egress_debug_info * egress_frame_debug_info)1889 mgmt_rx_reo_egress_frame_debug_info_enabled
1890 (struct reo_egress_debug_info *egress_frame_debug_info)
1891 {
1892 return egress_frame_debug_info->frame_list_size;
1893 }
1894
1895 /**
1896 * mgmt_rx_reo_debug_print_scheduler_stats() - API to print the stats
1897 * related to frames getting scheduled by mgmt rx reo scheduler
1898 * @reo_ctx: Pointer to reorder context
1899 *
1900 * API to print the stats related to frames getting scheduled by management
1901 * Rx reorder scheduler.
1902 *
1903 * Return: QDF_STATUS
1904 */
1905 static QDF_STATUS
mgmt_rx_reo_debug_print_scheduler_stats(struct mgmt_rx_reo_context * reo_ctx)1906 mgmt_rx_reo_debug_print_scheduler_stats(struct mgmt_rx_reo_context *reo_ctx)
1907 {
1908 struct reo_scheduler_stats *stats;
1909 uint64_t scheduled_count_per_link[MAX_MLO_LINKS] = {0};
1910 uint64_t scheduled_count_per_context[MGMT_RX_REO_CONTEXT_MAX] = {0};
1911 uint64_t total_scheduled_count = 0;
1912 uint64_t rescheduled_count_per_link[MAX_MLO_LINKS] = {0};
1913 uint64_t rescheduled_count_per_context[MGMT_RX_REO_CONTEXT_MAX] = {0};
1914 uint64_t total_rescheduled_count = 0;
1915 uint64_t total_scheduler_cb_count = 0;
1916 uint8_t link_id;
1917 uint8_t ctx;
1918
1919 if (!reo_ctx)
1920 return QDF_STATUS_E_NULL_VALUE;
1921
1922 stats = &reo_ctx->scheduler_debug_info.stats;
1923
1924 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
1925 for (ctx = 0; ctx < MGMT_RX_REO_CONTEXT_MAX; ctx++) {
1926 scheduled_count_per_link[link_id] +=
1927 stats->scheduled_count[link_id][ctx];
1928 rescheduled_count_per_link[link_id] +=
1929 stats->rescheduled_count[link_id][ctx];
1930 }
1931
1932 total_scheduled_count += scheduled_count_per_link[link_id];
1933 total_rescheduled_count += rescheduled_count_per_link[link_id];
1934 total_scheduler_cb_count += stats->scheduler_cb_count[link_id];
1935 }
1936
1937 for (ctx = 0; ctx < MGMT_RX_REO_CONTEXT_MAX; ctx++) {
1938 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
1939 scheduled_count_per_context[ctx] +=
1940 stats->scheduled_count[link_id][ctx];
1941 rescheduled_count_per_context[ctx] +=
1942 stats->rescheduled_count[link_id][ctx];
1943 }
1944 }
1945
1946 mgmt_rx_reo_alert("Scheduler stats:");
1947 mgmt_rx_reo_alert("\t1) Scheduled count");
1948 mgmt_rx_reo_alert("\t\t0 - MGMT_RX_REO_CONTEXT_MGMT_RX");
1949 mgmt_rx_reo_alert("\t\t1 - MGMT_RX_REO_CONTEXT_INGRESS_LIST_TIMEOUT");
1950 mgmt_rx_reo_alert("\t\t2 - MGMT_RX_REO_CONTEXT_SCHEDULER_CB");
1951 mgmt_rx_reo_alert("\t------------------------------------");
1952 mgmt_rx_reo_alert("\t|link id/ | | | |");
1953 mgmt_rx_reo_alert("\t|context | 0| 1| 2|");
1954 mgmt_rx_reo_alert("\t-------------------------------------------");
1955
1956 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
1957 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
1958 stats->scheduled_count[link_id][0],
1959 stats->scheduled_count[link_id][1],
1960 stats->scheduled_count[link_id][2],
1961 scheduled_count_per_link[link_id]);
1962 mgmt_rx_reo_alert("\t-------------------------------------------");
1963 }
1964 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
1965 scheduled_count_per_context[0],
1966 scheduled_count_per_context[1],
1967 scheduled_count_per_context[2],
1968 total_scheduled_count);
1969
1970 mgmt_rx_reo_alert("\t2) Rescheduled count");
1971 mgmt_rx_reo_alert("\t\t0 - MGMT_RX_REO_CONTEXT_MGMT_RX");
1972 mgmt_rx_reo_alert("\t\t1 - MGMT_RX_REO_CONTEXT_INGRESS_LIST_TIMEOUT");
1973 mgmt_rx_reo_alert("\t\t2 - MGMT_RX_REO_CONTEXT_SCHEDULER_CB");
1974 mgmt_rx_reo_alert("\t------------------------------------");
1975 mgmt_rx_reo_alert("\t|link id/ | | | |");
1976 mgmt_rx_reo_alert("\t|context | 0| 1| 2|");
1977 mgmt_rx_reo_alert("\t-------------------------------------------");
1978
1979 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
1980 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
1981 stats->rescheduled_count[link_id][0],
1982 stats->rescheduled_count[link_id][1],
1983 stats->rescheduled_count[link_id][2],
1984 rescheduled_count_per_link[link_id]);
1985 mgmt_rx_reo_alert("\t-------------------------------------------");
1986 }
1987 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
1988 rescheduled_count_per_context[0],
1989 rescheduled_count_per_context[1],
1990 rescheduled_count_per_context[2],
1991 total_rescheduled_count);
1992
1993 mgmt_rx_reo_alert("\t3) Per link stats:");
1994 mgmt_rx_reo_alert("\t----------------------");
1995 mgmt_rx_reo_alert("\t|link id|Scheduler CB|");
1996 mgmt_rx_reo_alert("\t| | Count |");
1997 mgmt_rx_reo_alert("\t----------------------");
1998
1999 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
2000 mgmt_rx_reo_alert("\t|%7u|%12llu|", link_id,
2001 stats->scheduler_cb_count[link_id]);
2002 mgmt_rx_reo_alert("\t----------------------");
2003 }
2004 mgmt_rx_reo_alert("\t%8s|%12llu|\n\n", "", total_scheduler_cb_count);
2005
2006 return QDF_STATUS_SUCCESS;
2007 }
2008
2009 /**
2010 * mgmt_rx_reo_debug_print_egress_frame_stats() - API to print the stats
2011 * related to frames going out of the reorder module
2012 * @reo_ctx: Pointer to reorder context
2013 *
2014 * API to print the stats related to frames going out of the management
2015 * Rx reorder module.
2016 *
2017 * Return: QDF_STATUS
2018 */
2019 static QDF_STATUS
mgmt_rx_reo_debug_print_egress_frame_stats(struct mgmt_rx_reo_context * reo_ctx)2020 mgmt_rx_reo_debug_print_egress_frame_stats(struct mgmt_rx_reo_context *reo_ctx)
2021 {
2022 struct reo_egress_frame_stats *stats;
2023 uint8_t link_id;
2024 uint8_t reason;
2025 uint8_t ctx;
2026 uint64_t total_delivery_attempts_count = 0;
2027 uint64_t total_delivery_success_count = 0;
2028 uint64_t total_drop_count = 0;
2029 uint64_t total_premature_delivery_count = 0;
2030 uint64_t delivery_count_per_link[MAX_MLO_LINKS] = {0};
2031 uint64_t delivery_count_per_reason[RELEASE_REASON_MAX] = {0};
2032 uint64_t delivery_count_per_context[MGMT_RX_REO_CONTEXT_MAX] = {0};
2033 uint64_t total_delivery_count = 0;
2034 char delivery_reason_stats_boarder_a[MGMT_RX_REO_EGRESS_FRAME_DELIVERY_REASON_STATS_BOARDER_A_MAX_SIZE + 1] = {0};
2035 char delivery_reason_stats_boarder_b[MGMT_RX_REO_EGRESS_FRAME_DELIVERY_REASON_STATS_BOARDER_B_MAX_SIZE + 1] = {0};
2036 QDF_STATUS status;
2037
2038 if (!reo_ctx)
2039 return QDF_STATUS_E_NULL_VALUE;
2040
2041 stats = &reo_ctx->egress_frame_debug_info.stats;
2042
2043 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
2044 total_delivery_attempts_count +=
2045 stats->delivery_attempts_count[link_id];
2046 total_delivery_success_count +=
2047 stats->delivery_success_count[link_id];
2048 total_drop_count += stats->drop_count[link_id];
2049 total_premature_delivery_count +=
2050 stats->premature_delivery_count[link_id];
2051 }
2052
2053 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
2054 for (reason = 0; reason < RELEASE_REASON_MAX;
2055 reason++)
2056 delivery_count_per_link[link_id] +=
2057 stats->delivery_reason_count[link_id][reason];
2058 total_delivery_count += delivery_count_per_link[link_id];
2059 }
2060 for (reason = 0; reason < RELEASE_REASON_MAX; reason++)
2061 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++)
2062 delivery_count_per_reason[reason] +=
2063 stats->delivery_reason_count[link_id][reason];
2064 for (ctx = 0; ctx < MGMT_RX_REO_CONTEXT_MAX; ctx++)
2065 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++)
2066 delivery_count_per_context[ctx] +=
2067 stats->delivery_context_count[link_id][ctx];
2068
2069 mgmt_rx_reo_alert("Egress frame stats:");
2070 mgmt_rx_reo_alert("\t1) Delivery related stats:");
2071 mgmt_rx_reo_alert("\t------------------------------------------------");
2072 mgmt_rx_reo_alert("\t|link id |Attempts|Success |Premature|Drop |");
2073 mgmt_rx_reo_alert("\t| | count | count | count |count |");
2074 mgmt_rx_reo_alert("\t------------------------------------------------");
2075 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
2076 mgmt_rx_reo_alert("\t|%9u|%8llu|%8llu|%9llu|%8llu|", link_id,
2077 stats->delivery_attempts_count[link_id],
2078 stats->delivery_success_count[link_id],
2079 stats->premature_delivery_count[link_id],
2080 stats->drop_count[link_id]);
2081 mgmt_rx_reo_alert("\t------------------------------------------------");
2082 }
2083 mgmt_rx_reo_alert("\t%10s|%8llu|%8llu|%9llu|%8llu|\n\n", "",
2084 total_delivery_attempts_count,
2085 total_delivery_success_count,
2086 total_premature_delivery_count,
2087 total_drop_count);
2088
2089 mgmt_rx_reo_alert("\t2) Delivery reason related stats");
2090 mgmt_rx_reo_alert("\tRelease Reason Values:-");
2091 mgmt_rx_reo_alert("\tREASON_ZERO_WAIT_COUNT - 0x%lx",
2092 RELEASE_REASON_ZERO_WAIT_COUNT);
2093 mgmt_rx_reo_alert("\tREASON_AGED_OUT - 0x%lx",
2094 RELEASE_REASON_AGED_OUT);
2095 mgmt_rx_reo_alert("\tREASON_OLDER_THAN_AGED_OUT_FRAME - 0x%lx",
2096 RELEASE_REASON_OLDER_THAN_AGED_OUT_FRAME);
2097 mgmt_rx_reo_alert("\tREASON_INGRESS_LIST_OVERFLOW - 0x%lx",
2098 RELEASE_REASON_INGRESS_LIST_OVERFLOW);
2099 mgmt_rx_reo_alert("\tREASON_OLDER_THAN_READY_TO_DELIVER_FRAMES - 0x%lx",
2100 RELEASE_REASON_OLDER_THAN_READY_TO_DELIVER_FRAMES);
2101 mgmt_rx_reo_alert("\tREASON_EGRESS_LIST_OVERFLOW - 0x%lx",
2102 RELEASE_REASON_EGRESS_LIST_OVERFLOW);
2103
2104 qdf_mem_set(delivery_reason_stats_boarder_a,
2105 MGMT_RX_REO_EGRESS_FRAME_DELIVERY_REASON_STATS_BOARDER_A_MAX_SIZE, '-');
2106 qdf_mem_set(delivery_reason_stats_boarder_b,
2107 MGMT_RX_REO_EGRESS_FRAME_DELIVERY_REASON_STATS_BOARDER_B_MAX_SIZE, '-');
2108
2109 mgmt_rx_reo_alert("\t%66s", delivery_reason_stats_boarder_a);
2110 mgmt_rx_reo_alert("\t|%16s|%7s|%7s|%7s|%7s|%7s|%7s|", "Release Reason/",
2111 "", "", "", "", "", "");
2112 mgmt_rx_reo_alert("\t|%16s|%7s|%7s|%7s|%7s|%7s|%7s|", "link id",
2113 "0", "1", "2", "3", "4", "5");
2114 mgmt_rx_reo_alert("\t%s", delivery_reason_stats_boarder_b);
2115
2116 for (reason = 0; reason < RELEASE_REASON_MAX; reason++) {
2117 mgmt_rx_reo_alert("\t|%16x|%7llu|%7llu|%7llu|%7llu|%7llu|%7llu|%7llu",
2118 reason,
2119 stats->delivery_reason_count[0][reason],
2120 stats->delivery_reason_count[1][reason],
2121 stats->delivery_reason_count[2][reason],
2122 stats->delivery_reason_count[3][reason],
2123 stats->delivery_reason_count[4][reason],
2124 stats->delivery_reason_count[5][reason],
2125 delivery_count_per_reason[reason]);
2126 mgmt_rx_reo_alert("\t%s", delivery_reason_stats_boarder_b);
2127 }
2128 mgmt_rx_reo_alert("\t%17s|%7llu|%7llu|%7llu|%7llu|%7llu|%7llu|%7llu\n\n",
2129 "", delivery_count_per_link[0],
2130 delivery_count_per_link[1],
2131 delivery_count_per_link[2],
2132 delivery_count_per_link[3],
2133 delivery_count_per_link[4],
2134 delivery_count_per_link[5],
2135 total_delivery_count);
2136
2137 mgmt_rx_reo_alert("\t3) Delivery context related stats");
2138 mgmt_rx_reo_alert("\t\t0 - MGMT_RX_REO_CONTEXT_MGMT_RX");
2139 mgmt_rx_reo_alert("\t\t1 - MGMT_RX_REO_CONTEXT_INGRESS_LIST_TIMEOUT");
2140 mgmt_rx_reo_alert("\t\t2 - MGMT_RX_REO_CONTEXT_SCHEDULER_CB");
2141 mgmt_rx_reo_alert("\t------------------------------------");
2142 mgmt_rx_reo_alert("\t|link id/ | | | |");
2143 mgmt_rx_reo_alert("\t|context | 0| 1| 2|");
2144 mgmt_rx_reo_alert("\t-------------------------------------------");
2145
2146 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
2147 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
2148 stats->delivery_context_count[link_id][0],
2149 stats->delivery_context_count[link_id][1],
2150 stats->delivery_context_count[link_id][2],
2151 delivery_count_per_link[link_id]);
2152 mgmt_rx_reo_alert("\t-------------------------------------------");
2153 }
2154 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
2155 delivery_count_per_context[0],
2156 delivery_count_per_context[1],
2157 delivery_count_per_context[2],
2158 total_delivery_count);
2159
2160 mgmt_rx_reo_alert("\t4) Misc stats:");
2161 mgmt_rx_reo_alert("\t\tEgress list overflow count = %llu\n\n",
2162 reo_ctx->egress_list.reo_list.overflow_count);
2163
2164 status = mgmt_rx_reo_debug_print_scheduler_stats(reo_ctx);
2165 if (QDF_IS_STATUS_ERROR(status)) {
2166 mgmt_rx_reo_err("Failed to print scheduler stats");
2167 return status;
2168 }
2169
2170 return QDF_STATUS_SUCCESS;
2171 }
2172
2173 /**
2174 * mgmt_rx_reo_log_egress_frame_before_delivery() - Log the information about a
2175 * frame exiting the reorder module. Logging is done before attempting the frame
2176 * delivery to upper layers.
2177 * @reo_ctx: management rx reorder context
2178 * @entry: Pointer to reorder list entry
2179 *
2180 * Return: QDF_STATUS of operation
2181 */
2182 static QDF_STATUS
mgmt_rx_reo_log_egress_frame_before_delivery(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_list_entry * entry)2183 mgmt_rx_reo_log_egress_frame_before_delivery(
2184 struct mgmt_rx_reo_context *reo_ctx,
2185 struct mgmt_rx_reo_list_entry *entry)
2186 {
2187 struct reo_egress_debug_info *egress_frame_debug_info;
2188 struct reo_egress_debug_frame_info *cur_frame_debug_info;
2189 struct reo_egress_frame_stats *stats;
2190 uint8_t link_id;
2191
2192 if (!reo_ctx || !entry)
2193 return QDF_STATUS_E_NULL_VALUE;
2194
2195 egress_frame_debug_info = &reo_ctx->egress_frame_debug_info;
2196
2197 stats = &egress_frame_debug_info->stats;
2198 link_id = mgmt_rx_reo_get_link_id(entry->rx_params);
2199 stats->delivery_attempts_count[link_id]++;
2200 if (entry->is_premature_delivery)
2201 stats->premature_delivery_count[link_id]++;
2202
2203 if (!mgmt_rx_reo_egress_frame_debug_info_enabled
2204 (egress_frame_debug_info))
2205 return QDF_STATUS_SUCCESS;
2206
2207 cur_frame_debug_info = &egress_frame_debug_info->frame_list
2208 [egress_frame_debug_info->next_index];
2209
2210 cur_frame_debug_info->link_id = link_id;
2211 cur_frame_debug_info->mgmt_pkt_ctr =
2212 mgmt_rx_reo_get_pkt_counter(entry->rx_params);
2213 cur_frame_debug_info->global_timestamp =
2214 mgmt_rx_reo_get_global_ts(entry->rx_params);
2215 cur_frame_debug_info->initial_wait_count = entry->initial_wait_count;
2216 cur_frame_debug_info->final_wait_count = entry->wait_count;
2217 qdf_mem_copy(cur_frame_debug_info->shared_snapshots,
2218 entry->shared_snapshots,
2219 qdf_min(sizeof(cur_frame_debug_info->shared_snapshots),
2220 sizeof(entry->shared_snapshots)));
2221 qdf_mem_copy(cur_frame_debug_info->host_snapshot, entry->host_snapshot,
2222 qdf_min(sizeof(cur_frame_debug_info->host_snapshot),
2223 sizeof(entry->host_snapshot)));
2224 cur_frame_debug_info->ingress_timestamp = entry->ingress_timestamp;
2225 cur_frame_debug_info->ingress_list_insertion_ts =
2226 entry->ingress_list_insertion_ts;
2227 cur_frame_debug_info->ingress_list_removal_ts =
2228 entry->ingress_list_removal_ts;
2229 cur_frame_debug_info->egress_list_insertion_ts =
2230 entry->egress_list_insertion_ts;
2231 cur_frame_debug_info->egress_list_removal_ts =
2232 entry->egress_list_removal_ts;
2233 cur_frame_debug_info->egress_timestamp = qdf_get_log_timestamp();
2234 cur_frame_debug_info->egress_list_size = entry->egress_list_size;
2235 cur_frame_debug_info->first_scheduled_ts = entry->first_scheduled_ts;
2236 cur_frame_debug_info->last_scheduled_ts = entry->last_scheduled_ts;
2237 cur_frame_debug_info->scheduled_count =
2238 qdf_atomic_read(&entry->scheduled_count);
2239 cur_frame_debug_info->ctx_info = entry->ctx_info;
2240 cur_frame_debug_info->release_reason = entry->release_reason;
2241 cur_frame_debug_info->is_premature_delivery =
2242 entry->is_premature_delivery;
2243 cur_frame_debug_info->cpu_id = qdf_get_smp_processor_id();
2244
2245 return QDF_STATUS_SUCCESS;
2246 }
2247
2248 /**
2249 * mgmt_rx_reo_log_egress_frame_after_delivery() - Log the information about a
2250 * frame exiting the reorder module. Logging is done after attempting the frame
2251 * delivery to upper layer.
2252 * @reo_ctx: management rx reorder context
2253 * @entry: Pointer to reorder list entry
2254 * @link_id: multi-link link ID
2255 *
2256 * Return: QDF_STATUS of operation
2257 */
2258 static QDF_STATUS
mgmt_rx_reo_log_egress_frame_after_delivery(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_list_entry * entry,uint8_t link_id)2259 mgmt_rx_reo_log_egress_frame_after_delivery(
2260 struct mgmt_rx_reo_context *reo_ctx,
2261 struct mgmt_rx_reo_list_entry *entry,
2262 uint8_t link_id)
2263 {
2264 struct reo_egress_debug_info *egress_frame_debug_info;
2265 struct reo_egress_debug_frame_info *cur_frame_debug_info;
2266 struct reo_egress_frame_stats *stats;
2267 uint8_t context;
2268
2269 if (!reo_ctx || !entry)
2270 return QDF_STATUS_E_NULL_VALUE;
2271
2272 egress_frame_debug_info = &reo_ctx->egress_frame_debug_info;
2273 context = entry->ctx_info.context;
2274 if (context >= MGMT_RX_REO_CONTEXT_MAX)
2275 return QDF_STATUS_E_INVAL;
2276
2277 stats = &egress_frame_debug_info->stats;
2278 if (entry->is_delivered) {
2279 uint8_t release_reason = entry->release_reason;
2280
2281 stats->delivery_reason_count[link_id][release_reason]++;
2282 stats->delivery_context_count[link_id][context]++;
2283 stats->delivery_success_count[link_id]++;
2284 }
2285
2286 if (entry->is_dropped)
2287 stats->drop_count[link_id]++;
2288
2289 if (!mgmt_rx_reo_egress_frame_debug_info_enabled
2290 (egress_frame_debug_info))
2291 return QDF_STATUS_SUCCESS;
2292
2293 cur_frame_debug_info = &egress_frame_debug_info->frame_list
2294 [egress_frame_debug_info->next_index];
2295
2296 cur_frame_debug_info->is_delivered = entry->is_delivered;
2297 cur_frame_debug_info->is_dropped = entry->is_dropped;
2298 cur_frame_debug_info->egress_duration = qdf_get_log_timestamp() -
2299 cur_frame_debug_info->egress_timestamp;
2300
2301 egress_frame_debug_info->next_index++;
2302 egress_frame_debug_info->next_index %=
2303 egress_frame_debug_info->frame_list_size;
2304 if (egress_frame_debug_info->next_index == 0)
2305 egress_frame_debug_info->wrap_aroud = true;
2306
2307 return QDF_STATUS_SUCCESS;
2308 }
2309
2310 /**
2311 * mgmt_rx_reo_debug_print_egress_frame_info() - Print the debug information
2312 * about the latest frames leaving the reorder module
2313 * @reo_ctx: management rx reorder context
2314 * @num_frames: Number of frames for which the debug information is to be
2315 * printed. If @num_frames is 0, then debug information about all the frames
2316 * in the ring buffer will be printed.
2317 *
2318 * Return: QDF_STATUS of operation
2319 */
2320 static QDF_STATUS
mgmt_rx_reo_debug_print_egress_frame_info(struct mgmt_rx_reo_context * reo_ctx,uint16_t num_frames)2321 mgmt_rx_reo_debug_print_egress_frame_info(struct mgmt_rx_reo_context *reo_ctx,
2322 uint16_t num_frames)
2323 {
2324 struct reo_egress_debug_info *egress_frame_debug_info;
2325 int start_index;
2326 uint16_t index;
2327 uint16_t entry;
2328 uint16_t num_valid_entries;
2329 uint16_t num_entries_to_print;
2330 char *boarder;
2331
2332 if (!reo_ctx)
2333 return QDF_STATUS_E_NULL_VALUE;
2334
2335 egress_frame_debug_info = &reo_ctx->egress_frame_debug_info;
2336
2337 if (egress_frame_debug_info->wrap_aroud)
2338 num_valid_entries = egress_frame_debug_info->frame_list_size;
2339 else
2340 num_valid_entries = egress_frame_debug_info->next_index;
2341
2342 if (num_frames == 0) {
2343 num_entries_to_print = num_valid_entries;
2344
2345 if (egress_frame_debug_info->wrap_aroud)
2346 start_index = egress_frame_debug_info->next_index;
2347 else
2348 start_index = 0;
2349 } else {
2350 num_entries_to_print = qdf_min(num_frames, num_valid_entries);
2351
2352 start_index = (egress_frame_debug_info->next_index -
2353 num_entries_to_print +
2354 egress_frame_debug_info->frame_list_size)
2355 % egress_frame_debug_info->frame_list_size;
2356 }
2357
2358 mgmt_rx_reo_alert_no_fl("Egress Frame Info:-");
2359 mgmt_rx_reo_alert_no_fl("num_frames = %u, wrap = %u, next_index = %u",
2360 num_frames,
2361 egress_frame_debug_info->wrap_aroud,
2362 egress_frame_debug_info->next_index);
2363 mgmt_rx_reo_alert_no_fl("start_index = %d num_entries_to_print = %u",
2364 start_index, num_entries_to_print);
2365
2366 if (!num_entries_to_print)
2367 return QDF_STATUS_SUCCESS;
2368
2369 boarder = egress_frame_debug_info->boarder;
2370
2371 mgmt_rx_reo_alert_no_fl("%s", boarder);
2372 mgmt_rx_reo_alert_no_fl("|%3s|%5s|%4s|%5s|%10s|%11s|%11s|%11s|%11s|%11s|%11s|%5s|%7s|%7s|%5s|%4s|%69s|%69s|%94s|%94s|%94s|%94s|%94s|%94s|",
2373 "No.", "CPU", "Link", "SeqNo", "Global ts",
2374 "Ingress ts", "Ing Insert",
2375 "Ing Remove", "Eg Insert", "Eg Remove",
2376 "Egress ts", "E Dur", "I W Dur", "E W Dur",
2377 "Flags", "Rea.", "Final wait count",
2378 "Initial wait count", "Snapshot : link 0",
2379 "Snapshot : link 1", "Snapshot : link 2",
2380 "Snapshot : link 3", "Snapshot : link 4",
2381 "Snapshot : link 5");
2382 mgmt_rx_reo_alert_no_fl("%s", boarder);
2383
2384 index = start_index;
2385 for (entry = 0; entry < num_entries_to_print; entry++) {
2386 struct reo_egress_debug_frame_info *info;
2387 char flags[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_FLAG_MAX_SIZE + 1] = {0};
2388 char final_wait_count[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_WAIT_COUNT_MAX_SIZE + 1] = {0};
2389 char initial_wait_count[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_WAIT_COUNT_MAX_SIZE + 1] = {0};
2390 char snapshots[MAX_MLO_LINKS][MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_PER_LINK_SNAPSHOTS_MAX_SIZE + 1] = {0};
2391 char flag_premature_delivery = ' ';
2392 char flag_error = ' ';
2393 uint8_t link;
2394
2395 info = &reo_ctx->egress_frame_debug_info.frame_list[index];
2396
2397 if (!info->is_delivered)
2398 flag_error = 'E';
2399
2400 if (info->is_premature_delivery)
2401 flag_premature_delivery = 'P';
2402
2403 snprintf(flags, sizeof(flags), "%c %c", flag_error,
2404 flag_premature_delivery);
2405 snprintf(initial_wait_count, sizeof(initial_wait_count),
2406 "%9llx(%8x, %8x, %8x, %8x, %8x, %8x)",
2407 info->initial_wait_count.total_count,
2408 info->initial_wait_count.per_link_count[0],
2409 info->initial_wait_count.per_link_count[1],
2410 info->initial_wait_count.per_link_count[2],
2411 info->initial_wait_count.per_link_count[3],
2412 info->initial_wait_count.per_link_count[4],
2413 info->initial_wait_count.per_link_count[5]);
2414 snprintf(final_wait_count, sizeof(final_wait_count),
2415 "%9llx(%8x, %8x, %8x, %8x, %8x, %8x)",
2416 info->final_wait_count.total_count,
2417 info->final_wait_count.per_link_count[0],
2418 info->final_wait_count.per_link_count[1],
2419 info->final_wait_count.per_link_count[2],
2420 info->final_wait_count.per_link_count[3],
2421 info->final_wait_count.per_link_count[4],
2422 info->final_wait_count.per_link_count[5]);
2423
2424 for (link = 0; link < MAX_MLO_LINKS; link++) {
2425 char mac_hw[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
2426 char fw_consumed[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
2427 char fw_forwarded[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
2428 char host[MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
2429 struct mgmt_rx_reo_snapshot_params *mac_hw_ss;
2430 struct mgmt_rx_reo_snapshot_params *fw_consumed_ss;
2431 struct mgmt_rx_reo_snapshot_params *fw_forwarded_ss;
2432 struct mgmt_rx_reo_snapshot_params *host_ss;
2433
2434 mac_hw_ss = &info->shared_snapshots
2435 [link][MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW];
2436 fw_consumed_ss = &info->shared_snapshots
2437 [link][MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED];
2438 fw_forwarded_ss = &info->shared_snapshots
2439 [link][MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED];
2440 host_ss = &info->host_snapshot[link];
2441
2442 snprintf(mac_hw, sizeof(mac_hw), "(%1u, %5u, %10u)",
2443 mac_hw_ss->valid, mac_hw_ss->mgmt_pkt_ctr,
2444 mac_hw_ss->global_timestamp);
2445 snprintf(fw_consumed, sizeof(fw_consumed),
2446 "(%1u, %5u, %10u)",
2447 fw_consumed_ss->valid,
2448 fw_consumed_ss->mgmt_pkt_ctr,
2449 fw_consumed_ss->global_timestamp);
2450 snprintf(fw_forwarded, sizeof(fw_forwarded),
2451 "(%1u, %5u, %10u)",
2452 fw_forwarded_ss->valid,
2453 fw_forwarded_ss->mgmt_pkt_ctr,
2454 fw_forwarded_ss->global_timestamp);
2455 snprintf(host, sizeof(host), "(%1u, %5u, %10u)",
2456 host_ss->valid,
2457 host_ss->mgmt_pkt_ctr,
2458 host_ss->global_timestamp);
2459 snprintf(snapshots[link], sizeof(snapshots[link]),
2460 "%22s, %22s, %22s, %22s", mac_hw, fw_consumed,
2461 fw_forwarded, host);
2462 }
2463
2464 mgmt_rx_reo_alert_no_fl("|%3u|%5d|%4u|%5u|%10u|%11llu|%11llu|%11llu|%11llu|%11llu|%11llu|%5llu|%7llu|%7llu|%5s|%4x|%69s|%69s|%94s|%94s|%94s|%94s|%94s|%94s|",
2465 entry, info->cpu_id, info->link_id,
2466 info->mgmt_pkt_ctr,
2467 info->global_timestamp,
2468 info->ingress_timestamp,
2469 info->ingress_list_insertion_ts,
2470 info->ingress_list_removal_ts,
2471 info->egress_list_insertion_ts,
2472 info->egress_list_removal_ts,
2473 info->egress_timestamp,
2474 info->egress_duration,
2475 info->ingress_list_removal_ts -
2476 info->ingress_list_insertion_ts,
2477 info->egress_list_removal_ts -
2478 info->egress_list_insertion_ts,
2479 flags, info->release_reason,
2480 final_wait_count, initial_wait_count,
2481 snapshots[0], snapshots[1],
2482 snapshots[2], snapshots[3],
2483 snapshots[4], snapshots[5]);
2484 mgmt_rx_reo_alert_no_fl("%s", boarder);
2485
2486 index++;
2487 index %= egress_frame_debug_info->frame_list_size;
2488 }
2489
2490 return QDF_STATUS_SUCCESS;
2491 }
2492 #else
2493 /**
2494 * mgmt_rx_reo_debug_print_egress_frame_stats() - API to print the stats
2495 * related to frames going out of the reorder module
2496 * @reo_ctx: Pointer to reorder context
2497 *
2498 * API to print the stats related to frames going out of the management
2499 * Rx reorder module.
2500 *
2501 * Return: QDF_STATUS
2502 */
2503 static QDF_STATUS
mgmt_rx_reo_debug_print_egress_frame_stats(struct mgmt_rx_reo_context * reo_ctx)2504 mgmt_rx_reo_debug_print_egress_frame_stats(struct mgmt_rx_reo_context *reo_ctx)
2505 {
2506 return QDF_STATUS_SUCCESS;
2507 }
2508
2509 /**
2510 * mgmt_rx_reo_log_egress_frame_before_delivery() - Log the information about a
2511 * frame exiting the reorder module. Logging is done before attempting the frame
2512 * delivery to upper layers.
2513 * @reo_ctx: management rx reorder context
2514 * @entry: Pointer to reorder list entry
2515 *
2516 * Return: QDF_STATUS of operation
2517 */
2518 static QDF_STATUS
mgmt_rx_reo_log_egress_frame_before_delivery(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_list_entry * entry)2519 mgmt_rx_reo_log_egress_frame_before_delivery(
2520 struct mgmt_rx_reo_context *reo_ctx,
2521 struct mgmt_rx_reo_list_entry *entry)
2522 {
2523 return QDF_STATUS_SUCCESS;
2524 }
2525
2526 /**
2527 * mgmt_rx_reo_log_egress_frame_after_delivery() - Log the information about a
2528 * frame exiting the reorder module. Logging is done after attempting the frame
2529 * delivery to upper layer.
2530 * @reo_ctx: management rx reorder context
2531 * @entry: Pointer to reorder list entry
2532 * @link_id: multi-link link ID
2533 *
2534 * Return: QDF_STATUS of operation
2535 */
2536 static QDF_STATUS
mgmt_rx_reo_log_egress_frame_after_delivery(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_list_entry * entry,uint8_t link_id)2537 mgmt_rx_reo_log_egress_frame_after_delivery(
2538 struct mgmt_rx_reo_context *reo_ctx,
2539 struct mgmt_rx_reo_list_entry *entry,
2540 uint8_t link_id)
2541 {
2542 return QDF_STATUS_SUCCESS;
2543 }
2544
2545 /**
2546 * mgmt_rx_reo_debug_print_egress_frame_info() - Print debug information about
2547 * the latest frames leaving the reorder module
2548 * @reo_ctx: management rx reorder context
2549 *
2550 * Return: QDF_STATUS of operation
2551 */
2552 static QDF_STATUS
mgmt_rx_reo_debug_print_egress_frame_info(struct mgmt_rx_reo_context * reo_ctx)2553 mgmt_rx_reo_debug_print_egress_frame_info(struct mgmt_rx_reo_context *reo_ctx)
2554 {
2555 return QDF_STATUS_SUCCESS;
2556 }
2557 #endif /* WLAN_MGMT_RX_REO_DEBUG_SUPPORT */
2558
2559 /**
2560 * mgmt_rx_reo_list_entry_get_release_reason() - Helper API to get the reason
2561 * for releasing the reorder list entry to upper layer.
2562 * reorder list.
2563 * @entry: List entry
2564 *
2565 * This API expects the caller to acquire the spin lock protecting the reorder
2566 * list.
2567 *
2568 * Return: Reason for releasing the frame.
2569 */
2570 static uint8_t
mgmt_rx_reo_list_entry_get_release_reason(struct mgmt_rx_reo_list_entry * entry)2571 mgmt_rx_reo_list_entry_get_release_reason(struct mgmt_rx_reo_list_entry *entry)
2572 {
2573 uint8_t reason = 0;
2574
2575 if (!entry)
2576 return 0;
2577
2578 if (!LIST_ENTRY_IS_WAITING_FOR_FRAME_ON_OTHER_LINK(entry))
2579 reason |= RELEASE_REASON_ZERO_WAIT_COUNT;
2580
2581 if (LIST_ENTRY_IS_AGED_OUT(entry))
2582 reason |= RELEASE_REASON_AGED_OUT;
2583
2584 if (LIST_ENTRY_IS_OLDER_THAN_LATEST_AGED_OUT_FRAME(entry))
2585 reason |= RELEASE_REASON_OLDER_THAN_AGED_OUT_FRAME;
2586
2587 if (LIST_ENTRY_IS_REMOVED_DUE_TO_INGRESS_LIST_OVERFLOW(entry))
2588 reason |= RELEASE_REASON_INGRESS_LIST_OVERFLOW;
2589
2590 if (LIST_ENTRY_IS_OLDER_THAN_READY_TO_DELIVER_FRAMES(entry))
2591 reason |= RELEASE_REASON_OLDER_THAN_READY_TO_DELIVER_FRAMES;
2592
2593 if (LIST_ENTRY_IS_REMOVED_DUE_TO_EGRESS_LIST_OVERFLOW(entry))
2594 reason |= RELEASE_REASON_EGRESS_LIST_OVERFLOW;
2595
2596 return reason;
2597 }
2598
2599 /**
2600 * mgmt_rx_reo_list_entry_send_up() - API to send the frame to the upper layer.
2601 * @reo_context: Pointer to reorder context
2602 * @entry: List entry
2603 * @deliver: Indicates whether this entry has to be delivered to upper layers
2604 * or dropped in the reo layer itself.
2605 *
2606 * API to send the frame to the upper layer. This API has to be called only
2607 * for entries which can be released to upper layer. It is the caller's
2608 * responsibility to ensure that entry can be released (by using API
2609 * mgmt_rx_reo_is_entry_ready_to_send_up). This API is called after
2610 * acquiring the lock which serializes the frame delivery to the upper layers.
2611 *
2612 * Return: QDF_STATUS
2613 */
2614 static QDF_STATUS
mgmt_rx_reo_list_entry_send_up(struct mgmt_rx_reo_context * reo_context,struct mgmt_rx_reo_list_entry * entry,bool deliver)2615 mgmt_rx_reo_list_entry_send_up(struct mgmt_rx_reo_context *reo_context,
2616 struct mgmt_rx_reo_list_entry *entry,
2617 bool deliver)
2618 {
2619 uint8_t release_reason;
2620 uint8_t link_id;
2621 uint32_t entry_global_ts;
2622 QDF_STATUS status;
2623 QDF_STATUS temp;
2624
2625 if (!reo_context) {
2626 mgmt_rx_reo_err("Reo context is null");
2627 return QDF_STATUS_E_NULL_VALUE;
2628 }
2629
2630 if (!entry) {
2631 mgmt_rx_reo_err("Entry is null");
2632 return QDF_STATUS_E_NULL_VALUE;
2633 }
2634
2635 link_id = mgmt_rx_reo_get_link_id(entry->rx_params);
2636 entry_global_ts = mgmt_rx_reo_get_global_ts(entry->rx_params);
2637
2638 release_reason = mgmt_rx_reo_list_entry_get_release_reason(entry);
2639 if (!release_reason) {
2640 mgmt_rx_reo_err("Release reason is zero");
2641 return QDF_STATUS_E_INVAL;
2642 }
2643
2644 entry->is_delivered = false;
2645 entry->is_dropped = false;
2646 entry->is_premature_delivery = false;
2647 entry->release_reason = release_reason;
2648
2649 if (mgmt_rx_reo_is_potential_premature_delivery(release_reason)) {
2650 entry->is_premature_delivery = true;
2651 status = mgmt_rx_reo_handle_potential_premature_delivery(
2652 reo_context, entry_global_ts);
2653 if (QDF_IS_STATUS_ERROR(status))
2654 goto exit;
2655 }
2656
2657 status = mgmt_rx_reo_log_egress_frame_before_delivery(reo_context,
2658 entry);
2659 if (QDF_IS_STATUS_ERROR(status))
2660 goto exit;
2661
2662 if (deliver) {
2663 status = wlan_mgmt_txrx_process_rx_frame(entry->pdev,
2664 entry->nbuf,
2665 entry->rx_params);
2666 /* Above call frees nbuf and rx_params, make them null */
2667 entry->nbuf = NULL;
2668 entry->rx_params = NULL;
2669
2670 if (QDF_IS_STATUS_ERROR(status))
2671 goto exit_log;
2672
2673 entry->is_delivered = true;
2674 } else {
2675 free_mgmt_rx_event_params(entry->rx_params);
2676 qdf_nbuf_free(entry->nbuf);
2677 entry->is_dropped = true;
2678 }
2679
2680 status = QDF_STATUS_SUCCESS;
2681
2682 exit_log:
2683 temp = mgmt_rx_reo_log_egress_frame_after_delivery(reo_context, entry,
2684 link_id);
2685 if (QDF_IS_STATUS_ERROR(temp))
2686 status = temp;
2687 exit:
2688 /**
2689 * Release the reference taken when the entry is inserted into
2690 * the reorder list
2691 */
2692 wlan_objmgr_pdev_release_ref(entry->pdev, WLAN_MGMT_RX_REO_ID);
2693
2694 return status;
2695 }
2696
2697 /**
2698 * mgmt_rx_reo_is_entry_ready_to_send_up() - API to check whether the
2699 * list entry can be send to upper layers.
2700 * @entry: List entry
2701 *
2702 * Return: QDF_STATUS
2703 */
2704 static bool
mgmt_rx_reo_is_entry_ready_to_send_up(struct mgmt_rx_reo_list_entry * entry)2705 mgmt_rx_reo_is_entry_ready_to_send_up(struct mgmt_rx_reo_list_entry *entry)
2706 {
2707 if (!entry) {
2708 mgmt_rx_reo_err("Entry is null");
2709 return false;
2710 }
2711
2712 return LIST_ENTRY_IS_REMOVED_DUE_TO_INGRESS_LIST_OVERFLOW(entry) ||
2713 LIST_ENTRY_IS_REMOVED_DUE_TO_EGRESS_LIST_OVERFLOW(entry) ||
2714 !LIST_ENTRY_IS_WAITING_FOR_FRAME_ON_OTHER_LINK(entry) ||
2715 LIST_ENTRY_IS_AGED_OUT(entry) ||
2716 LIST_ENTRY_IS_OLDER_THAN_LATEST_AGED_OUT_FRAME(entry) ||
2717 LIST_ENTRY_IS_OLDER_THAN_READY_TO_DELIVER_FRAMES(entry);
2718 }
2719
2720 #ifdef WLAN_MGMT_RX_REO_DEBUG_SUPPORT
2721 /**
2722 * mgmt_rx_reo_scheduler_debug_info_enabled() - API to check whether scheduler
2723 * debug feaure is enabled
2724 * @scheduler_debug_info: Pointer to scheduler debug info object
2725 *
2726 * Return: true or false
2727 */
2728 static bool
mgmt_rx_reo_scheduler_debug_info_enabled(struct reo_scheduler_debug_info * scheduler_debug_info)2729 mgmt_rx_reo_scheduler_debug_info_enabled
2730 (struct reo_scheduler_debug_info *scheduler_debug_info)
2731 {
2732 return scheduler_debug_info->frame_list_size;
2733 }
2734
2735 /**
2736 * mgmt_rx_reo_log_scheduler_debug_info() - Log the information about a
2737 * frame getting scheduled by mgmt rx reo scheduler
2738 * @reo_ctx: management rx reorder context
2739 * @entry: Pointer to reorder list entry
2740 * @reschedule: Indicates rescheduling
2741 *
2742 * Return: QDF_STATUS of operation
2743 */
2744 static QDF_STATUS
mgmt_rx_reo_log_scheduler_debug_info(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_list_entry * entry,bool reschedule)2745 mgmt_rx_reo_log_scheduler_debug_info(struct mgmt_rx_reo_context *reo_ctx,
2746 struct mgmt_rx_reo_list_entry *entry,
2747 bool reschedule)
2748 {
2749 struct reo_scheduler_debug_info *scheduler_debug_info;
2750 struct reo_scheduler_debug_frame_info *cur_frame_debug_info;
2751 struct reo_scheduler_stats *stats;
2752 uint8_t link_id;
2753
2754 if (!reo_ctx || !entry)
2755 return QDF_STATUS_E_NULL_VALUE;
2756
2757 scheduler_debug_info = &reo_ctx->scheduler_debug_info;
2758
2759 stats = &scheduler_debug_info->stats;
2760 link_id = mgmt_rx_reo_get_link_id(entry->rx_params);
2761 stats->scheduled_count[link_id][entry->ctx_info.context]++;
2762 if (reschedule)
2763 stats->rescheduled_count[link_id][entry->ctx_info.context]++;
2764
2765 if (!mgmt_rx_reo_scheduler_debug_info_enabled(scheduler_debug_info))
2766 return QDF_STATUS_SUCCESS;
2767
2768 cur_frame_debug_info = &scheduler_debug_info->frame_list
2769 [scheduler_debug_info->next_index];
2770
2771 cur_frame_debug_info->link_id = link_id;
2772 cur_frame_debug_info->mgmt_pkt_ctr =
2773 mgmt_rx_reo_get_pkt_counter(entry->rx_params);
2774 cur_frame_debug_info->global_timestamp =
2775 mgmt_rx_reo_get_global_ts(entry->rx_params);
2776 cur_frame_debug_info->initial_wait_count = entry->initial_wait_count;
2777 cur_frame_debug_info->final_wait_count = entry->wait_count;
2778 qdf_mem_copy(cur_frame_debug_info->shared_snapshots,
2779 entry->shared_snapshots,
2780 qdf_min(sizeof(cur_frame_debug_info->shared_snapshots),
2781 sizeof(entry->shared_snapshots)));
2782 qdf_mem_copy(cur_frame_debug_info->host_snapshot, entry->host_snapshot,
2783 qdf_min(sizeof(cur_frame_debug_info->host_snapshot),
2784 sizeof(entry->host_snapshot)));
2785 cur_frame_debug_info->ingress_timestamp = entry->ingress_timestamp;
2786 cur_frame_debug_info->ingress_list_insertion_ts =
2787 entry->ingress_list_insertion_ts;
2788 cur_frame_debug_info->ingress_list_removal_ts =
2789 entry->ingress_list_removal_ts;
2790 cur_frame_debug_info->egress_list_insertion_ts =
2791 entry->egress_list_insertion_ts;
2792 cur_frame_debug_info->scheduled_ts = qdf_get_log_timestamp();
2793 cur_frame_debug_info->first_scheduled_ts = entry->first_scheduled_ts;
2794 cur_frame_debug_info->last_scheduled_ts = entry->last_scheduled_ts;
2795 cur_frame_debug_info->scheduled_count =
2796 qdf_atomic_read(&entry->scheduled_count);
2797 cur_frame_debug_info->cpu_id = qdf_get_smp_processor_id();
2798 cur_frame_debug_info->ctx_info = entry->ctx_info;
2799
2800 scheduler_debug_info->next_index++;
2801 scheduler_debug_info->next_index %=
2802 scheduler_debug_info->frame_list_size;
2803 if (scheduler_debug_info->next_index == 0)
2804 scheduler_debug_info->wrap_aroud = true;
2805
2806 return QDF_STATUS_SUCCESS;
2807 }
2808 #else
2809 /**
2810 * mgmt_rx_reo_log_scheduler_debug_info() - Log the information about a
2811 * frame getting scheduled by mgmt rx reo scheduler
2812 * @reo_ctx: management rx reorder context
2813 * @entry: Pointer to reorder list entry
2814 * @reschedule: Indicates rescheduling
2815 *
2816 * Return: QDF_STATUS of operation
2817 */
2818 static inline QDF_STATUS
mgmt_rx_reo_log_scheduler_debug_info(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_list_entry * entry,bool reschedule)2819 mgmt_rx_reo_log_scheduler_debug_info(struct mgmt_rx_reo_context *reo_ctx,
2820 struct mgmt_rx_reo_list_entry *entry,
2821 bool reschedule)
2822 {
2823 return QDF_STATUS_SUCCESS;
2824 }
2825 #endif /* WLAN_MGMT_RX_REO_DEBUG_SUPPORT */
2826
2827 /**
2828 * mgmt_rx_reo_defer_delivery() - Helper API to check whether a management
2829 * frame can be delivered in the current context or it has to be scheduled
2830 * for delivery in a different context
2831 * @entry: List entry
2832 * @link_bitmap: Link bitmap
2833 *
2834 * Return: true if frame can't be delivered in the current context and its
2835 * delivery has to be done in a different context
2836 */
2837 bool
mgmt_rx_reo_defer_delivery(struct mgmt_rx_reo_list_entry * entry,uint32_t link_bitmap)2838 mgmt_rx_reo_defer_delivery(struct mgmt_rx_reo_list_entry *entry,
2839 uint32_t link_bitmap)
2840 {
2841 uint8_t link_id;
2842 uint8_t mlo_grp_id;
2843 struct wlan_objmgr_pdev *pdev;
2844
2845 if (!entry) {
2846 mgmt_rx_reo_err("Entry is null");
2847 return true;
2848 }
2849
2850 link_id = mgmt_rx_reo_get_link_id(entry->rx_params);
2851 mlo_grp_id = entry->rx_params->reo_params->mlo_grp_id;
2852
2853 pdev = wlan_get_pdev_from_mlo_link_id(link_id, mlo_grp_id,
2854 WLAN_MGMT_RX_REO_ID);
2855 if (!pdev) {
2856 mgmt_rx_reo_err("pdev for link %u, group %u is null",
2857 link_id, mlo_grp_id);
2858 return false;
2859 }
2860
2861 if (!wlan_mgmt_rx_reo_is_scheduler_enabled_at_pdev(pdev)) {
2862 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
2863 return false;
2864 }
2865
2866 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
2867
2868 return !(link_bitmap & (1 << link_id));
2869 }
2870
2871 /**
2872 * mgmt_rx_reo_schedule_delivery() - Helper API to schedule the delivery of
2873 * a management frames.
2874 * @reo_context: Pointer to reorder context
2875 * @entry: List entry corresponding to the frame which has to be scheduled
2876 * for delivery
2877 *
2878 * Return: QDF_STATUS
2879 */
2880 QDF_STATUS
mgmt_rx_reo_schedule_delivery(struct mgmt_rx_reo_context * reo_context,struct mgmt_rx_reo_list_entry * entry)2881 mgmt_rx_reo_schedule_delivery(struct mgmt_rx_reo_context *reo_context,
2882 struct mgmt_rx_reo_list_entry *entry)
2883 {
2884 int scheduled_count;
2885 int8_t link_id;
2886 uint8_t mlo_grp_id;
2887 struct wlan_objmgr_pdev *pdev;
2888 QDF_STATUS status;
2889 bool reschedule;
2890
2891 if (!reo_context) {
2892 mgmt_rx_reo_err("Reo context is null");
2893 return QDF_STATUS_E_NULL_VALUE;
2894 }
2895
2896 if (!entry) {
2897 mgmt_rx_reo_err("List entry is null");
2898 return QDF_STATUS_E_NULL_VALUE;
2899 }
2900
2901 scheduled_count = qdf_atomic_inc_return(&entry->scheduled_count);
2902
2903 reschedule = (scheduled_count > 1);
2904 status = mgmt_rx_reo_log_scheduler_debug_info(reo_context, entry,
2905 reschedule);
2906 if (QDF_IS_STATUS_ERROR(status)) {
2907 mgmt_rx_reo_err("Failed to log scheduler debug info");
2908 return status;
2909 }
2910
2911 if (reschedule) {
2912 entry->last_scheduled_ts = qdf_get_log_timestamp();
2913 return QDF_STATUS_SUCCESS;
2914 }
2915
2916 link_id = mgmt_rx_reo_get_link_id(entry->rx_params);
2917 mlo_grp_id = entry->rx_params->reo_params->mlo_grp_id;
2918 pdev = wlan_get_pdev_from_mlo_link_id(link_id, mlo_grp_id,
2919 WLAN_MGMT_RX_REO_ID);
2920 if (!pdev) {
2921 mgmt_rx_reo_err("pdev for link %u, group %u is null",
2922 link_id, mlo_grp_id);
2923 return QDF_STATUS_E_NULL_VALUE;
2924 }
2925
2926 entry->first_scheduled_ts = qdf_get_log_timestamp();
2927 status = tgt_mgmt_rx_reo_schedule_delivery(wlan_pdev_get_psoc(pdev));
2928 if (QDF_IS_STATUS_ERROR(status)) {
2929 mgmt_rx_reo_err("Failed to schedule for link %u, group %u",
2930 link_id, mlo_grp_id);
2931 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
2932 return status;
2933 }
2934 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
2935
2936 return QDF_STATUS_SUCCESS;
2937 }
2938
2939 /**
2940 * mgmt_rx_reo_release_egress_list_entries() - Release entries from the
2941 * egress list
2942 * @reo_context: Pointer to management Rx reorder context
2943 * @link_bitmap: Bitmap of links for which frames can be released in the current
2944 * context
2945 * @ctx: Current execution context info
2946 *
2947 * This API releases the entries from the egress list based on the following
2948 * conditions.
2949 * a) Entries with total wait count equal to 0
2950 * b) Entries which are timed out or entries with global time stamp <= global
2951 * time stamp of the latest frame which is timed out. We can only release
2952 * the entries in the increasing order of the global time stamp.
2953 * So all the entries with global time stamp <= global time stamp of the
2954 * latest timed out frame has to be released.
2955 *
2956 * Return: QDF_STATUS
2957 */
2958 static QDF_STATUS
mgmt_rx_reo_release_egress_list_entries(struct mgmt_rx_reo_context * reo_context,uint32_t link_bitmap,struct mgmt_rx_reo_context_info * ctx)2959 mgmt_rx_reo_release_egress_list_entries(struct mgmt_rx_reo_context *reo_context,
2960 uint32_t link_bitmap,
2961 struct mgmt_rx_reo_context_info *ctx)
2962 {
2963 QDF_STATUS status;
2964 struct mgmt_rx_reo_egress_list *egress_list;
2965 struct mgmt_rx_reo_list *reo_egress_list;
2966 qdf_timer_t *egress_inactivity_timer;
2967
2968 if (!reo_context) {
2969 mgmt_rx_reo_err("reo context is null");
2970 return QDF_STATUS_E_NULL_VALUE;
2971 }
2972
2973 egress_list = &reo_context->egress_list;
2974 reo_egress_list = &egress_list->reo_list;
2975 egress_inactivity_timer = &egress_list->egress_inactivity_timer;
2976
2977 qdf_spin_lock(&reo_context->frame_release_lock);
2978
2979 while (1) {
2980 struct mgmt_rx_reo_list_entry *first_entry;
2981 /* TODO yield if release_count > THRESHOLD */
2982 uint16_t release_count = 0;
2983 uint32_t first_entry_ts;
2984 struct mgmt_rx_event_params *rx_params;
2985 struct mgmt_rx_reo_frame_info *last_released_frame =
2986 &reo_egress_list->last_released_frame;
2987 uint32_t last_released_frame_ts;
2988 bool ready;
2989 bool defer;
2990 bool overflow;
2991
2992 qdf_spin_lock_bh(&reo_egress_list->list_lock);
2993
2994 first_entry = qdf_list_first_entry_or_null(
2995 &reo_egress_list->list,
2996 struct mgmt_rx_reo_list_entry, node);
2997 if (!first_entry) {
2998 status = QDF_STATUS_SUCCESS;
2999 goto exit_unlock_egress_list_lock;
3000 }
3001
3002 ready = mgmt_rx_reo_is_entry_ready_to_send_up(first_entry);
3003 if (!ready) {
3004 status = QDF_STATUS_E_FAILURE;
3005 goto exit_unlock_egress_list_lock;
3006 }
3007
3008 first_entry->ctx_info = *ctx;
3009 defer = mgmt_rx_reo_defer_delivery(first_entry, link_bitmap);
3010 overflow =
3011 LIST_ENTRY_IS_REMOVED_DUE_TO_EGRESS_LIST_OVERFLOW(first_entry);
3012 if (defer && !overflow) {
3013 status = mgmt_rx_reo_schedule_delivery(reo_context,
3014 first_entry);
3015 if (QDF_IS_STATUS_ERROR(status))
3016 mgmt_rx_reo_err("Failed to schedule delivery");
3017 goto exit_unlock_egress_list_lock;
3018 }
3019
3020 first_entry->egress_list_size =
3021 qdf_list_size(&reo_egress_list->list);
3022 status = qdf_list_remove_node(&reo_egress_list->list,
3023 &first_entry->node);
3024 if (QDF_IS_STATUS_ERROR(status)) {
3025 status = QDF_STATUS_E_FAILURE;
3026 goto exit_unlock_egress_list_lock;
3027 }
3028 first_entry->egress_list_removal_ts = qdf_get_log_timestamp();
3029
3030 /**
3031 * Last released frame global time stamp is invalid means that
3032 * current frame is the first frame to be released to the
3033 * upper layer from the egress list. Blindly update the last
3034 * released frame global time stamp to the current frame's
3035 * global time stamp and set the valid to true.
3036 * If the last released frame global time stamp is valid and
3037 * current frame's global time stamp is >= last released frame
3038 * global time stamp, deliver the current frame to upper layer
3039 * and update the last released frame global time stamp.
3040 */
3041 rx_params = first_entry->rx_params;
3042 first_entry_ts = mgmt_rx_reo_get_global_ts(rx_params);
3043 last_released_frame_ts =
3044 last_released_frame->reo_params.global_timestamp;
3045
3046 if (!last_released_frame->valid ||
3047 mgmt_rx_reo_compare_global_timestamps_gte(
3048 first_entry_ts, last_released_frame_ts)) {
3049 qdf_timer_sync_cancel(egress_inactivity_timer);
3050
3051 last_released_frame->reo_params =
3052 *rx_params->reo_params;
3053 last_released_frame->valid = true;
3054
3055 qdf_timer_mod(egress_inactivity_timer,
3056 MGMT_RX_REO_EGRESS_INACTIVITY_TIMEOUT);
3057 } else {
3058 /**
3059 * This should never happen. All the frames older than
3060 * the last frame released from the reorder list will be
3061 * discarded at the entry to reorder algorithm itself.
3062 */
3063 qdf_assert_always(first_entry->is_parallel_rx);
3064 }
3065
3066 qdf_spin_unlock_bh(&reo_egress_list->list_lock);
3067
3068 status = mgmt_rx_reo_list_entry_send_up(reo_context,
3069 first_entry,
3070 !defer || !overflow);
3071 if (QDF_IS_STATUS_ERROR(status)) {
3072 status = QDF_STATUS_E_FAILURE;
3073 qdf_mem_free(first_entry);
3074 goto exit_unlock_frame_release_lock;
3075 }
3076
3077 qdf_mem_free(first_entry);
3078 release_count++;
3079 }
3080
3081 status = QDF_STATUS_SUCCESS;
3082 goto exit_unlock_frame_release_lock;
3083
3084 exit_unlock_egress_list_lock:
3085 if (qdf_list_size(&reo_egress_list->list) >
3086 reo_egress_list->max_list_size)
3087 mgmt_rx_reo_err("Egress list overflow size =%u, max = %u",
3088 qdf_list_size(&reo_egress_list->list),
3089 reo_egress_list->max_list_size);
3090 qdf_spin_unlock_bh(&reo_egress_list->list_lock);
3091 exit_unlock_frame_release_lock:
3092 qdf_spin_unlock(&reo_context->frame_release_lock);
3093
3094 return status;
3095 }
3096
3097 #ifdef WLAN_MGMT_RX_REO_DEBUG_SUPPORT
3098 /**
3099 * mgmt_rx_reo_scheduler_cb_stats_inc() - API to increment scheduler_cb_count.
3100 * @link_bitmap: Bitmap of links for which frames can be released in the current
3101 * context
3102 * @reo_context: Pointer to management Rx reorder context
3103 *
3104 * This API increments the scheduler_cb_count of links for which frames can be
3105 * released in the current context
3106 */
mgmt_rx_reo_scheduler_cb_stats_inc(uint32_t link_bitmap,struct mgmt_rx_reo_context * reo_context)3107 static void mgmt_rx_reo_scheduler_cb_stats_inc(uint32_t link_bitmap,
3108 struct mgmt_rx_reo_context
3109 *reo_context)
3110 {
3111 uint8_t link;
3112
3113 for (link = 0; link < MAX_MLO_LINKS; link++)
3114 if (link_bitmap & (1 << link)) {
3115 struct reo_scheduler_stats *stats;
3116
3117 stats = &reo_context->scheduler_debug_info.stats;
3118 stats->scheduler_cb_count[link]++;
3119 }
3120 }
3121 #else
mgmt_rx_reo_scheduler_cb_stats_inc(uint32_t link_bitmap,struct mgmt_rx_reo_context * reo_context)3122 static void mgmt_rx_reo_scheduler_cb_stats_inc(uint32_t link_bitmap,
3123 struct mgmt_rx_reo_context
3124 *reo_context)
3125 {
3126 }
3127 #endif
3128
3129 QDF_STATUS
mgmt_rx_reo_release_frames(uint8_t mlo_grp_id,uint32_t link_bitmap)3130 mgmt_rx_reo_release_frames(uint8_t mlo_grp_id, uint32_t link_bitmap)
3131 {
3132 struct mgmt_rx_reo_context *reo_context;
3133 QDF_STATUS ret;
3134 struct mgmt_rx_reo_context_info ctx_info = {0};
3135
3136 if (mlo_grp_id >= WLAN_MAX_MLO_GROUPS) {
3137 mgmt_rx_reo_err("Invalid mlo grp id");
3138 return QDF_STATUS_E_INVAL;
3139 }
3140
3141 reo_context = mgmt_rx_reo_get_context(mlo_grp_id);
3142 if (!reo_context) {
3143 mgmt_rx_reo_err("Mgmt rx reo context is null");
3144 return QDF_STATUS_E_NULL_VALUE;
3145 }
3146 mgmt_rx_reo_scheduler_cb_stats_inc(link_bitmap, reo_context);
3147 ctx_info.context = MGMT_RX_REO_CONTEXT_SCHEDULER_CB;
3148 ctx_info.context_id = qdf_atomic_inc_return(&reo_context->context_id);
3149 ret = mgmt_rx_reo_release_egress_list_entries(reo_context, link_bitmap,
3150 &ctx_info);
3151 if (QDF_IS_STATUS_ERROR(ret)) {
3152 mgmt_rx_reo_err("Failure to release frames grp = %u bm = 0x%x",
3153 mlo_grp_id, link_bitmap);
3154 return ret;
3155 }
3156
3157 return QDF_STATUS_SUCCESS;
3158 }
3159
3160 /**
3161 * mgmt_rx_reo_check_sanity_list() - Check the sanity of reorder list
3162 * @reo_list: Pointer to reorder list
3163 *
3164 * Check the sanity of ingress reorder list or egress reorder list.
3165 * Ingress/Egress reorder list entries should be in the non decreasing order
3166 * of global time stamp.
3167 *
3168 * Return: QDF_STATUS
3169 */
3170 static QDF_STATUS
mgmt_rx_reo_check_sanity_list(struct mgmt_rx_reo_list * reo_list)3171 mgmt_rx_reo_check_sanity_list(struct mgmt_rx_reo_list *reo_list)
3172 {
3173 struct mgmt_rx_reo_list_entry *first;
3174 struct mgmt_rx_reo_list_entry *cur;
3175 uint32_t ts_prev;
3176 uint32_t ts_cur;
3177
3178 if (!reo_list) {
3179 mgmt_rx_reo_err("Reo list is null");
3180 return QDF_STATUS_E_NULL_VALUE;
3181 }
3182
3183 if (qdf_list_empty(&reo_list->list))
3184 return QDF_STATUS_SUCCESS;
3185
3186 first = qdf_list_first_entry_or_null(&reo_list->list,
3187 struct mgmt_rx_reo_list_entry,
3188 node);
3189 if (!first) {
3190 mgmt_rx_reo_err("First entry is null");
3191 return QDF_STATUS_E_NULL_VALUE;
3192 }
3193
3194 cur = first;
3195 ts_prev = mgmt_rx_reo_get_global_ts(first->rx_params);
3196
3197 qdf_list_for_each_continue(&reo_list->list, cur, node) {
3198 ts_cur = mgmt_rx_reo_get_global_ts(cur->rx_params);
3199
3200 if (!mgmt_rx_reo_compare_global_timestamps_gte(ts_cur,
3201 ts_prev))
3202 return QDF_STATUS_E_INVAL;
3203
3204 ts_prev = ts_cur;
3205 }
3206
3207 return QDF_STATUS_SUCCESS;
3208 }
3209
3210 /**
3211 * mgmt_rx_reo_check_sanity_lists() - Check the sanity of ingress and
3212 * egress reorder lists
3213 * @reo_egress_list: Pointer to egress reorder list
3214 * @reo_ingress_list: Pointer to ingress reorder list
3215 *
3216 * Check the sanity of ingress reorder list and egress reorder list.
3217 * This API does the following sanity checks.
3218 *
3219 * 1. Ingress list entries should be in the non decreasing order of global
3220 * time stamp.
3221 * 2. Egress list entries should be in the non decreasing order of global
3222 * time stamp.
3223 * 3. All the entries in egress list should have global time stamp less
3224 * than or equal to all the entries in ingress list.
3225 *
3226 * Return: QDF_STATUS
3227 */
3228 static QDF_STATUS
mgmt_rx_reo_check_sanity_lists(struct mgmt_rx_reo_list * reo_egress_list,struct mgmt_rx_reo_list * reo_ingress_list)3229 mgmt_rx_reo_check_sanity_lists(struct mgmt_rx_reo_list *reo_egress_list,
3230 struct mgmt_rx_reo_list *reo_ingress_list)
3231 {
3232 QDF_STATUS status;
3233 struct mgmt_rx_reo_list_entry *last_entry_egress_list;
3234 uint32_t ts_egress_last_entry;
3235 struct mgmt_rx_reo_list_entry *first_entry_ingress_list;
3236 uint32_t ts_ingress_first_entry;
3237
3238 if (!reo_egress_list) {
3239 mgmt_rx_reo_err("Egress list is null");
3240 return QDF_STATUS_E_NULL_VALUE;
3241 }
3242
3243 if (!reo_ingress_list) {
3244 mgmt_rx_reo_err("Ingress list is null");
3245 return QDF_STATUS_E_NULL_VALUE;
3246 }
3247
3248 status = mgmt_rx_reo_check_sanity_list(reo_egress_list);
3249 if (QDF_IS_STATUS_ERROR(status)) {
3250 mgmt_rx_reo_err("Sanity check of egress list failed");
3251 return status;
3252 }
3253
3254 status = mgmt_rx_reo_check_sanity_list(reo_ingress_list);
3255 if (QDF_IS_STATUS_ERROR(status)) {
3256 mgmt_rx_reo_err("Sanity check of ingress list failed");
3257 return status;
3258 }
3259
3260 if (qdf_list_empty(&reo_egress_list->list) ||
3261 qdf_list_empty(&reo_ingress_list->list))
3262 return QDF_STATUS_SUCCESS;
3263
3264 last_entry_egress_list =
3265 qdf_list_last_entry(&reo_egress_list->list,
3266 struct mgmt_rx_reo_list_entry, node);
3267 ts_egress_last_entry =
3268 mgmt_rx_reo_get_global_ts(last_entry_egress_list->rx_params);
3269
3270 first_entry_ingress_list =
3271 qdf_list_first_entry_or_null(&reo_ingress_list->list,
3272 struct mgmt_rx_reo_list_entry,
3273 node);
3274 if (!first_entry_ingress_list) {
3275 mgmt_rx_reo_err("Ingress list is expected to be non empty");
3276 return QDF_STATUS_E_INVAL;
3277 }
3278
3279 ts_ingress_first_entry =
3280 mgmt_rx_reo_get_global_ts(first_entry_ingress_list->rx_params);
3281
3282 if (!mgmt_rx_reo_compare_global_timestamps_gte(ts_ingress_first_entry,
3283 ts_egress_last_entry))
3284 return QDF_STATUS_E_INVAL;
3285
3286 return QDF_STATUS_SUCCESS;
3287 }
3288
3289 /**
3290 * mgmt_rx_reo_handle_egress_overflow() - Handle overflow of management
3291 * rx reorder egress list
3292 * @reo_egress_list: Pointer to egress reorder list
3293 *
3294 * API to handle overflow of management rx reorder egress list.
3295 *
3296 * Return: QDF_STATUS
3297 */
3298 static QDF_STATUS
mgmt_rx_reo_handle_egress_overflow(struct mgmt_rx_reo_list * reo_egress_list)3299 mgmt_rx_reo_handle_egress_overflow(struct mgmt_rx_reo_list *reo_egress_list)
3300 {
3301 struct mgmt_rx_reo_list_entry *cur_entry;
3302 uint32_t egress_list_max_size;
3303 uint32_t egress_list_cur_size;
3304 uint32_t num_overflow_frames;
3305
3306 if (!reo_egress_list) {
3307 mgmt_rx_reo_err("Egress reorder list is null");
3308 return QDF_STATUS_E_NULL_VALUE;
3309 }
3310
3311 reo_egress_list->overflow_count++;
3312 reo_egress_list->last_overflow_ts = qdf_get_log_timestamp();
3313 mgmt_rx_reo_debug_rl("Egress overflow, cnt:%llu size:%u",
3314 reo_egress_list->overflow_count,
3315 qdf_list_size(&reo_egress_list->list));
3316
3317 egress_list_cur_size = qdf_list_size(&reo_egress_list->list);
3318 egress_list_max_size = reo_egress_list->max_list_size;
3319 num_overflow_frames = egress_list_cur_size - egress_list_max_size;
3320
3321 qdf_list_for_each(&reo_egress_list->list, cur_entry, node) {
3322 if (num_overflow_frames > 0) {
3323 cur_entry->status |= STATUS_EGRESS_LIST_OVERFLOW;
3324 num_overflow_frames--;
3325 }
3326 }
3327
3328 return QDF_STATUS_SUCCESS;
3329 }
3330
3331 /**
3332 * mgmt_rx_reo_move_entries_ingress_to_egress_list() - Moves frames in
3333 * the ingress list which are ready to be delivered to the egress list
3334 * @ingress_list: Pointer to ingress list
3335 * @egress_list: Pointer to egress list
3336 *
3337 * This API moves frames in the ingress list which are ready to be delivered
3338 * to the egress list.
3339 *
3340 * Return: QDF_STATUS
3341 */
3342 static QDF_STATUS
mgmt_rx_reo_move_entries_ingress_to_egress_list(struct mgmt_rx_reo_ingress_list * ingress_list,struct mgmt_rx_reo_egress_list * egress_list)3343 mgmt_rx_reo_move_entries_ingress_to_egress_list
3344 (struct mgmt_rx_reo_ingress_list *ingress_list,
3345 struct mgmt_rx_reo_egress_list *egress_list)
3346 {
3347 struct mgmt_rx_reo_list *reo_ingress_list;
3348 struct mgmt_rx_reo_list *reo_egress_list;
3349 QDF_STATUS status;
3350 struct mgmt_rx_reo_list_entry *ingress_list_entry;
3351 struct mgmt_rx_reo_list_entry *latest_frame_ready_to_deliver = NULL;
3352 uint16_t num_frames_ready_to_deliver = 0;
3353 uint32_t num_overflow_frames = 0;
3354 uint32_t ingress_list_max_size;
3355 uint32_t ingress_list_cur_size;
3356
3357 if (!ingress_list) {
3358 mgmt_rx_reo_err("Ingress list is null");
3359 return QDF_STATUS_E_NULL_VALUE;
3360 }
3361 reo_ingress_list = &ingress_list->reo_list;
3362
3363 if (!egress_list) {
3364 mgmt_rx_reo_err("Egress list is null");
3365 return QDF_STATUS_E_NULL_VALUE;
3366 }
3367 reo_egress_list = &egress_list->reo_list;
3368
3369 qdf_spin_lock_bh(&reo_ingress_list->list_lock);
3370
3371 ingress_list_cur_size = qdf_list_size(&reo_ingress_list->list);
3372 ingress_list_max_size = reo_ingress_list->max_list_size;
3373 if (mgmt_rx_reo_list_overflowed(reo_ingress_list))
3374 num_overflow_frames =
3375 ingress_list_cur_size - ingress_list_max_size;
3376
3377 qdf_list_for_each(&reo_ingress_list->list, ingress_list_entry, node) {
3378 if (num_overflow_frames > 0) {
3379 ingress_list_entry->status |=
3380 STATUS_INGRESS_LIST_OVERFLOW;
3381 num_overflow_frames--;
3382 }
3383
3384 if (!mgmt_rx_reo_is_entry_ready_to_send_up(ingress_list_entry))
3385 break;
3386
3387 ingress_list_entry->ingress_list_removal_ts =
3388 qdf_get_log_timestamp();
3389 ingress_list_entry->egress_list_insertion_ts =
3390 qdf_get_log_timestamp();
3391 latest_frame_ready_to_deliver = ingress_list_entry;
3392 num_frames_ready_to_deliver++;
3393 }
3394
3395 /* Check if ingress list has at least one frame ready to be delivered */
3396 if (num_frames_ready_to_deliver) {
3397 qdf_list_t temp_list_frames_to_deliver;
3398
3399 qdf_list_create(&temp_list_frames_to_deliver,
3400 INGRESS_TO_EGRESS_MOVEMENT_TEMP_LIST_MAX_SIZE);
3401
3402 status = qdf_list_split(&temp_list_frames_to_deliver,
3403 &reo_ingress_list->list,
3404 &latest_frame_ready_to_deliver->node);
3405 if (QDF_IS_STATUS_ERROR(status)) {
3406 mgmt_rx_reo_err("Failed to split list");
3407 qdf_list_destroy(&temp_list_frames_to_deliver);
3408 goto exit_unlock_ingress_list;
3409 }
3410
3411 if (num_frames_ready_to_deliver !=
3412 qdf_list_size(&temp_list_frames_to_deliver)) {
3413 uint32_t list_size;
3414
3415 list_size = qdf_list_size(&temp_list_frames_to_deliver);
3416 mgmt_rx_reo_err("Mismatch in frames ready %u and %u",
3417 num_frames_ready_to_deliver,
3418 list_size);
3419 status = QDF_STATUS_E_INVAL;
3420 qdf_list_destroy(&temp_list_frames_to_deliver);
3421 goto exit_unlock_ingress_list;
3422 }
3423
3424 qdf_spin_lock_bh(&reo_egress_list->list_lock);
3425
3426 status = qdf_list_join(&reo_egress_list->list,
3427 &temp_list_frames_to_deliver);
3428 if (QDF_IS_STATUS_ERROR(status)) {
3429 mgmt_rx_reo_err("Failed to join lists");
3430 qdf_list_destroy(&temp_list_frames_to_deliver);
3431 goto exit_unlock_egress_and_ingress_list;
3432 }
3433
3434 if (mgmt_rx_reo_list_overflowed(reo_egress_list)) {
3435 status =
3436 mgmt_rx_reo_handle_egress_overflow(reo_egress_list);
3437 if (QDF_IS_STATUS_ERROR(status)) {
3438 mgmt_rx_reo_err("Failed to handle overflow");
3439 qdf_list_destroy(&temp_list_frames_to_deliver);
3440 goto exit_unlock_egress_and_ingress_list;
3441 }
3442 }
3443
3444 status = mgmt_rx_reo_check_sanity_lists(reo_egress_list,
3445 reo_ingress_list);
3446 if (QDF_IS_STATUS_ERROR(status)) {
3447 mgmt_rx_reo_err("Sanity check of reo lists failed");
3448 qdf_list_destroy(&temp_list_frames_to_deliver);
3449 goto exit_unlock_egress_and_ingress_list;
3450 }
3451
3452 qdf_spin_unlock_bh(&reo_egress_list->list_lock);
3453
3454 qdf_list_destroy(&temp_list_frames_to_deliver);
3455 }
3456
3457 status = QDF_STATUS_SUCCESS;
3458 goto exit_unlock_ingress_list;
3459
3460 exit_unlock_egress_and_ingress_list:
3461 qdf_spin_unlock_bh(&reo_egress_list->list_lock);
3462 exit_unlock_ingress_list:
3463 qdf_spin_unlock_bh(&reo_ingress_list->list_lock);
3464
3465 return status;
3466 }
3467
3468 /**
3469 * mgmt_rx_reo_ageout_entries_ingress_list() - Helper API to ageout entries
3470 * in the ingress list
3471 * @ingress_list: Pointer to the ingress list
3472 * @latest_aged_out_entry: Double pointer to the latest agedout entry in the
3473 * ingress list
3474 *
3475 * Helper API to ageout entries in the ingress list.
3476 *
3477 * Return: QDF_STATUS
3478 */
3479 static QDF_STATUS
mgmt_rx_reo_ageout_entries_ingress_list(struct mgmt_rx_reo_ingress_list * ingress_list,struct mgmt_rx_reo_list_entry ** latest_aged_out_entry)3480 mgmt_rx_reo_ageout_entries_ingress_list
3481 (struct mgmt_rx_reo_ingress_list *ingress_list,
3482 struct mgmt_rx_reo_list_entry **latest_aged_out_entry)
3483 {
3484 struct mgmt_rx_reo_list *reo_ingress_list;
3485 struct mgmt_rx_reo_list_entry *cur_entry;
3486 uint64_t cur_ts;
3487
3488 if (!ingress_list) {
3489 mgmt_rx_reo_err("Ingress list is null");
3490 return QDF_STATUS_E_NULL_VALUE;
3491 }
3492
3493 if (!latest_aged_out_entry) {
3494 mgmt_rx_reo_err("Latest aged out entry is null");
3495 return QDF_STATUS_E_NULL_VALUE;
3496 }
3497
3498 *latest_aged_out_entry = NULL;
3499 reo_ingress_list = &ingress_list->reo_list;
3500
3501 qdf_spin_lock_bh(&reo_ingress_list->list_lock);
3502
3503 cur_ts = qdf_get_log_timestamp();
3504
3505 qdf_list_for_each(&reo_ingress_list->list, cur_entry, node) {
3506 if (cur_ts - cur_entry->ingress_list_insertion_ts >=
3507 ingress_list->list_entry_timeout_us) {
3508 *latest_aged_out_entry = cur_entry;
3509 cur_entry->status |= STATUS_AGED_OUT;
3510 }
3511 }
3512
3513 if (!*latest_aged_out_entry)
3514 goto exit_release_list_lock;
3515
3516 qdf_list_for_each(&reo_ingress_list->list, cur_entry, node) {
3517 if (cur_entry == *latest_aged_out_entry)
3518 break;
3519 cur_entry->status |= STATUS_OLDER_THAN_LATEST_AGED_OUT_FRAME;
3520 }
3521
3522 exit_release_list_lock:
3523 qdf_spin_unlock_bh(&reo_ingress_list->list_lock);
3524
3525 return QDF_STATUS_SUCCESS;
3526 }
3527
3528 /**
3529 * mgmt_rx_reo_ingress_list_ageout_timer_handler() - Periodic ageout timer
3530 * handler
3531 * @arg: Argument to timer handler
3532 *
3533 * This is the handler for periodic ageout timer used to timeout entries in the
3534 * ingress list.
3535 *
3536 * Return: void
3537 */
3538 static void
mgmt_rx_reo_ingress_list_ageout_timer_handler(void * arg)3539 mgmt_rx_reo_ingress_list_ageout_timer_handler(void *arg)
3540 {
3541 struct mgmt_rx_reo_ingress_list *ingress_list = arg;
3542 struct mgmt_rx_reo_egress_list *egress_list;
3543 QDF_STATUS ret;
3544 struct mgmt_rx_reo_context *reo_ctx;
3545 /**
3546 * Stores the pointer to the entry in ingress list for the latest aged
3547 * out frame. Latest aged out frame is the aged out frame in reorder
3548 * list which has the largest global time stamp value.
3549 */
3550 struct mgmt_rx_reo_list_entry *latest_aged_out_entry = NULL;
3551 struct mgmt_rx_reo_context_info ctx_info = {0};
3552
3553 if (!ingress_list) {
3554 mgmt_rx_reo_err("Ingress list is null");
3555 return;
3556 }
3557
3558 reo_ctx = mgmt_rx_reo_get_context_from_ingress_list(ingress_list);
3559 if (!reo_ctx) {
3560 mgmt_rx_reo_err("Reo context is null");
3561 return;
3562 }
3563 egress_list = &reo_ctx->egress_list;
3564
3565 qdf_timer_mod(&ingress_list->ageout_timer,
3566 MGMT_RX_REO_INGRESS_LIST_AGEOUT_TIMER_PERIOD_MS);
3567
3568 ret = mgmt_rx_reo_ageout_entries_ingress_list(ingress_list,
3569 &latest_aged_out_entry);
3570 if (QDF_IS_STATUS_ERROR(ret)) {
3571 mgmt_rx_reo_err("Failure to ageout entries in ingress list");
3572 return;
3573 }
3574
3575 if (!latest_aged_out_entry)
3576 return;
3577
3578 ret = mgmt_rx_reo_move_entries_ingress_to_egress_list(ingress_list,
3579 egress_list);
3580 if (QDF_IS_STATUS_ERROR(ret)) {
3581 mgmt_rx_reo_err("Ingress to egress list movement failure(%d)",
3582 ret);
3583 return;
3584 }
3585
3586 ctx_info.context = MGMT_RX_REO_CONTEXT_INGRESS_LIST_TIMEOUT;
3587 ctx_info.context_id = qdf_atomic_inc_return(&reo_ctx->context_id);
3588 ret = mgmt_rx_reo_release_egress_list_entries(reo_ctx, 0, &ctx_info);
3589 if (QDF_IS_STATUS_ERROR(ret)) {
3590 mgmt_rx_reo_err("Failure to release entries, ret = %d", ret);
3591 return;
3592 }
3593 }
3594
3595 /**
3596 * mgmt_rx_reo_egress_inactivity_timer_handler() - Timer handler
3597 * for egress inactivity timer
3598 * @arg: Argument to timer handler
3599 *
3600 * This is the timer handler for tracking management Rx inactivity
3601 * across links.
3602 *
3603 * Return: void
3604 */
3605 static void
mgmt_rx_reo_egress_inactivity_timer_handler(void * arg)3606 mgmt_rx_reo_egress_inactivity_timer_handler(void *arg)
3607 {
3608 struct mgmt_rx_reo_egress_list *egress_list = arg;
3609 struct mgmt_rx_reo_list *reo_egress_list;
3610 struct mgmt_rx_reo_frame_info *last_delivered_frame;
3611
3612 if (!egress_list) {
3613 mgmt_rx_reo_err("Egress list is null");
3614 return;
3615 }
3616
3617 reo_egress_list = &egress_list->reo_list;
3618 last_delivered_frame = &reo_egress_list->last_released_frame;
3619
3620 qdf_spin_lock(&reo_egress_list->list_lock);
3621
3622 qdf_mem_zero(last_delivered_frame, sizeof(*last_delivered_frame));
3623
3624 qdf_spin_unlock(&reo_egress_list->list_lock);
3625 }
3626
3627 /**
3628 * mgmt_rx_reo_prepare_list_entry() - Prepare a list entry from the management
3629 * frame received.
3630 * @frame_desc: Pointer to the frame descriptor
3631 * @entry: Pointer to the list entry
3632 *
3633 * This API prepares the reorder list entry corresponding to a management frame
3634 * to be consumed by host. This entry would be inserted at the appropriate
3635 * position in the reorder list.
3636 *
3637 * Return: QDF_STATUS
3638 */
3639 static QDF_STATUS
mgmt_rx_reo_prepare_list_entry(const struct mgmt_rx_reo_frame_descriptor * frame_desc,struct mgmt_rx_reo_list_entry ** entry)3640 mgmt_rx_reo_prepare_list_entry(
3641 const struct mgmt_rx_reo_frame_descriptor *frame_desc,
3642 struct mgmt_rx_reo_list_entry **entry)
3643 {
3644 struct mgmt_rx_reo_list_entry *list_entry;
3645 struct wlan_objmgr_pdev *pdev;
3646 uint8_t link_id;
3647 uint8_t ml_grp_id;
3648
3649 if (!frame_desc) {
3650 mgmt_rx_reo_err("frame descriptor is null");
3651 return QDF_STATUS_E_NULL_VALUE;
3652 }
3653
3654 if (!entry) {
3655 mgmt_rx_reo_err("Pointer to list entry is null");
3656 return QDF_STATUS_E_NULL_VALUE;
3657 }
3658
3659 link_id = mgmt_rx_reo_get_link_id(frame_desc->rx_params);
3660 ml_grp_id = mgmt_rx_reo_get_mlo_grp_id(frame_desc->rx_params);
3661
3662 pdev = wlan_get_pdev_from_mlo_link_id(link_id, ml_grp_id,
3663 WLAN_MGMT_RX_REO_ID);
3664 if (!pdev) {
3665 mgmt_rx_reo_err("pdev corresponding to link %u is null",
3666 link_id);
3667 return QDF_STATUS_E_NULL_VALUE;
3668 }
3669
3670 list_entry = qdf_mem_malloc(sizeof(*list_entry));
3671 if (!list_entry) {
3672 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_ID);
3673 mgmt_rx_reo_err("List entry allocation failed");
3674 return QDF_STATUS_E_NOMEM;
3675 }
3676
3677 list_entry->pdev = pdev;
3678 list_entry->nbuf = frame_desc->nbuf;
3679 list_entry->rx_params = frame_desc->rx_params;
3680 list_entry->wait_count = frame_desc->wait_count;
3681 list_entry->initial_wait_count = frame_desc->wait_count;
3682 qdf_mem_copy(list_entry->shared_snapshots, frame_desc->shared_snapshots,
3683 qdf_min(sizeof(list_entry->shared_snapshots),
3684 sizeof(frame_desc->shared_snapshots)));
3685 qdf_mem_copy(list_entry->host_snapshot, frame_desc->host_snapshot,
3686 qdf_min(sizeof(list_entry->host_snapshot),
3687 sizeof(frame_desc->host_snapshot)));
3688 list_entry->status = 0;
3689 if (list_entry->wait_count.total_count)
3690 list_entry->status |= STATUS_WAIT_FOR_FRAME_ON_OTHER_LINKS;
3691 qdf_atomic_init(&list_entry->scheduled_count);
3692
3693 *entry = list_entry;
3694
3695 return QDF_STATUS_SUCCESS;
3696 }
3697
3698 /**
3699 * mgmt_rx_reo_update_wait_count() - Update the wait count for a frame based
3700 * on the wait count of a frame received after that on air.
3701 * @wait_count_old_frame: Pointer to the wait count structure for the old frame.
3702 * @wait_count_new_frame: Pointer to the wait count structure for the new frame.
3703 *
3704 * This API optimizes the wait count of a frame based on the wait count of
3705 * a frame received after that on air. Old frame refers to the frame received
3706 * first on the air and new frame refers to the frame received after that.
3707 * We use the following fundamental idea. Wait counts for old frames can't be
3708 * more than wait counts for the new frame. Use this to optimize the wait count
3709 * for the old frames. Per link wait count of an old frame is minimum of the
3710 * per link wait count of the old frame and new frame.
3711 *
3712 * Return: QDF_STATUS
3713 */
3714 static QDF_STATUS
mgmt_rx_reo_update_wait_count(struct mgmt_rx_reo_wait_count * wait_count_old_frame,const struct mgmt_rx_reo_wait_count * wait_count_new_frame)3715 mgmt_rx_reo_update_wait_count(
3716 struct mgmt_rx_reo_wait_count *wait_count_old_frame,
3717 const struct mgmt_rx_reo_wait_count *wait_count_new_frame)
3718 {
3719 uint8_t link_id;
3720
3721 if (!wait_count_old_frame) {
3722 mgmt_rx_reo_err("Pointer to old frame wait count is null");
3723 return QDF_STATUS_E_NULL_VALUE;
3724 }
3725
3726 if (!wait_count_new_frame) {
3727 mgmt_rx_reo_err("Pointer to new frame wait count is null");
3728 return QDF_STATUS_E_NULL_VALUE;
3729 }
3730
3731 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
3732 if (wait_count_old_frame->per_link_count[link_id]) {
3733 uint32_t temp_wait_count;
3734 uint32_t wait_count_diff;
3735
3736 temp_wait_count =
3737 wait_count_old_frame->per_link_count[link_id];
3738 wait_count_old_frame->per_link_count[link_id] =
3739 qdf_min(wait_count_old_frame->
3740 per_link_count[link_id],
3741 wait_count_new_frame->
3742 per_link_count[link_id]);
3743 wait_count_diff = temp_wait_count -
3744 wait_count_old_frame->per_link_count[link_id];
3745
3746 wait_count_old_frame->total_count -= wait_count_diff;
3747 }
3748 }
3749
3750 return QDF_STATUS_SUCCESS;
3751 }
3752
3753 /**
3754 * mgmt_rx_reo_update_ingress_list() - Modify the reorder list when a frame is
3755 * received
3756 * @ingress_list: Pointer to ingress list
3757 * @frame_desc: Pointer to frame descriptor
3758 * @new: pointer to the list entry for the current frame
3759 * @is_queued: Whether this frame is queued in the REO list
3760 *
3761 * API to update the reorder list on every management frame reception.
3762 * This API does the following things.
3763 * a) Update the wait counts for all the frames in the reorder list with
3764 * global time stamp <= current frame's global time stamp. We use the
3765 * following principle for updating the wait count in this case.
3766 * Let A and B be two management frames with global time stamp of A <=
3767 * global time stamp of B. Let WAi and WBi be the wait count of A and B
3768 * for link i, then WAi <= WBi. Hence we can optimize WAi as
3769 * min(WAi, WBi).
3770 * b) If the current frame is to be consumed by host, insert it in the
3771 * reorder list such that the list is always sorted in the increasing order
3772 * of global time stamp. Update the wait count of the current frame based
3773 * on the frame next to it in the reorder list (if any).
3774 * c) Update the wait count of the frames in the reorder list with global
3775 * time stamp > current frame's global time stamp. Let the current frame
3776 * belong to link "l". Then link "l"'s wait count can be reduced by one for
3777 * all the frames in the reorder list with global time stamp > current
3778 * frame's global time stamp.
3779 *
3780 * Return: QDF_STATUS
3781 */
3782 static QDF_STATUS
mgmt_rx_reo_update_ingress_list(struct mgmt_rx_reo_ingress_list * ingress_list,struct mgmt_rx_reo_frame_descriptor * frame_desc,struct mgmt_rx_reo_list_entry * new,bool * is_queued)3783 mgmt_rx_reo_update_ingress_list(struct mgmt_rx_reo_ingress_list *ingress_list,
3784 struct mgmt_rx_reo_frame_descriptor *frame_desc,
3785 struct mgmt_rx_reo_list_entry *new,
3786 bool *is_queued)
3787 {
3788 struct mgmt_rx_reo_list *reo_ingress_list;
3789 struct mgmt_rx_reo_list_entry *cur;
3790 struct mgmt_rx_reo_list_entry *least_greater = NULL;
3791 bool least_greater_entry_found = false;
3792 QDF_STATUS status;
3793 uint16_t list_insertion_pos = 0;
3794 uint32_t ts_new;
3795
3796 if (!ingress_list) {
3797 mgmt_rx_reo_err("Mgmt Rx reo ingress list is null");
3798 return QDF_STATUS_E_NULL_VALUE;
3799 }
3800 reo_ingress_list = &ingress_list->reo_list;
3801
3802 if (!frame_desc) {
3803 mgmt_rx_reo_err("Mgmt frame descriptor is null");
3804 return QDF_STATUS_E_NULL_VALUE;
3805 }
3806
3807 if (!(frame_desc->type == MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME &&
3808 frame_desc->reo_required) != !new) {
3809 mgmt_rx_reo_err("Invalid input");
3810 return QDF_STATUS_E_INVAL;
3811 }
3812
3813 if (!is_queued) {
3814 mgmt_rx_reo_err("Pointer to queued indication is null");
3815 return QDF_STATUS_E_NULL_VALUE;
3816 }
3817 *is_queued = false;
3818
3819 /**
3820 * In some cases, the current frame and its associated
3821 * rx_params/reo_params may get freed immediately after the frame
3822 * is queued to egress list. Hence fetching the global time stamp from
3823 * "frame_desc->rx_params->reo_params" could lead to use after free.
3824 * Store a copy of "reo_params" in the frame descriptor and access
3825 * the copy after the frame is queued to egress list.
3826 *
3827 * TODO:- Fix this cleanly using refcount mechanism or structure
3828 * duplication.
3829 */
3830 ts_new = frame_desc->reo_params_copy.global_timestamp;
3831
3832 frame_desc->ingress_list_size_rx =
3833 qdf_list_size(&reo_ingress_list->list);
3834
3835 qdf_list_for_each(&reo_ingress_list->list, cur, node) {
3836 uint32_t ts_cur;
3837
3838 ts_cur = mgmt_rx_reo_get_global_ts(cur->rx_params);
3839
3840 least_greater_entry_found =
3841 !mgmt_rx_reo_compare_global_timestamps_gte(ts_new, ts_cur);
3842 if (least_greater_entry_found) {
3843 least_greater = cur;
3844 break;
3845 }
3846
3847 qdf_assert_always(!frame_desc->is_stale || cur->is_parallel_rx);
3848
3849 list_insertion_pos++;
3850
3851 status = mgmt_rx_reo_update_wait_count(&cur->wait_count,
3852 &frame_desc->wait_count);
3853 if (QDF_IS_STATUS_ERROR(status))
3854 return status;
3855
3856 if (cur->wait_count.total_count == 0)
3857 cur->status &= ~STATUS_WAIT_FOR_FRAME_ON_OTHER_LINKS;
3858 }
3859
3860 if (frame_desc->type == MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME &&
3861 !frame_desc->is_stale && frame_desc->reo_required &&
3862 (frame_desc->queued_list != MGMT_RX_REO_LIST_TYPE_EGRESS)) {
3863 bool overflow;
3864
3865 if (least_greater_entry_found) {
3866 status = mgmt_rx_reo_update_wait_count(
3867 &new->wait_count,
3868 &least_greater->wait_count);
3869
3870 if (QDF_IS_STATUS_ERROR(status))
3871 return status;
3872
3873 frame_desc->wait_count = new->wait_count;
3874
3875 if (new->wait_count.total_count == 0)
3876 new->status &=
3877 ~STATUS_WAIT_FOR_FRAME_ON_OTHER_LINKS;
3878 }
3879
3880 new->ingress_list_insertion_ts = qdf_get_log_timestamp();
3881 new->ingress_timestamp = frame_desc->ingress_timestamp;
3882 new->is_parallel_rx = frame_desc->is_parallel_rx;
3883 frame_desc->ingress_list_insertion_pos = list_insertion_pos;
3884
3885 if (least_greater_entry_found)
3886 status = qdf_list_insert_before(
3887 &reo_ingress_list->list, &new->node,
3888 &least_greater->node);
3889 else
3890 status = qdf_list_insert_back(
3891 &reo_ingress_list->list, &new->node);
3892
3893 if (QDF_IS_STATUS_ERROR(status))
3894 return status;
3895
3896 *is_queued = true;
3897 frame_desc->queued_list = MGMT_RX_REO_LIST_TYPE_INGRESS;
3898
3899 overflow = (qdf_list_size(&reo_ingress_list->list) >
3900 reo_ingress_list->max_list_size);
3901 if (overflow) {
3902 qdf_list_t *ingress_list_ptr = &reo_ingress_list->list;
3903
3904 reo_ingress_list->overflow_count++;
3905 reo_ingress_list->last_overflow_ts =
3906 qdf_get_log_timestamp();
3907 mgmt_rx_reo_debug_rl("Ingress ovrflw, cnt:%llu size:%u",
3908 reo_ingress_list->overflow_count,
3909 qdf_list_size(ingress_list_ptr));
3910 }
3911
3912 if (new->wait_count.total_count == 0)
3913 frame_desc->zero_wait_count_rx = true;
3914
3915 if (frame_desc->zero_wait_count_rx &&
3916 qdf_list_first_entry_or_null(&reo_ingress_list->list,
3917 struct mgmt_rx_reo_list_entry,
3918 node) == new)
3919 frame_desc->immediate_delivery = true;
3920 }
3921
3922 if (least_greater_entry_found) {
3923 cur = least_greater;
3924
3925 qdf_list_for_each_from(&reo_ingress_list->list, cur, node) {
3926 uint8_t frame_link_id;
3927 struct mgmt_rx_reo_wait_count *wait_count;
3928
3929 /**
3930 * In some cases, the current frame and its associated
3931 * rx_params/reo_params may get freed immediately after
3932 * the frame is queued to egress list. Hence fetching
3933 * the link ID from
3934 * "frame_desc->rx_params->reo_params" could lead to
3935 * use after free. Store a copy of "reo_params" in the
3936 * frame descriptor and access the copy after the frame
3937 * is queued to egress list.
3938 *
3939 * TODO:- Fix this cleanly using refcount mechanism or
3940 * structure duplication.
3941 */
3942 frame_link_id = frame_desc->reo_params_copy.link_id;
3943 wait_count = &cur->wait_count;
3944 if (wait_count->per_link_count[frame_link_id]) {
3945 uint32_t old_wait_count;
3946 uint32_t new_wait_count;
3947 uint32_t wait_count_diff;
3948 uint16_t pkt_ctr_delta;
3949
3950 pkt_ctr_delta = frame_desc->pkt_ctr_delta;
3951 old_wait_count =
3952 wait_count->per_link_count[frame_link_id];
3953
3954 if (old_wait_count >= pkt_ctr_delta)
3955 new_wait_count = old_wait_count -
3956 pkt_ctr_delta;
3957 else
3958 new_wait_count = 0;
3959
3960 wait_count_diff = old_wait_count -
3961 new_wait_count;
3962
3963 wait_count->per_link_count[frame_link_id] =
3964 new_wait_count;
3965 wait_count->total_count -= wait_count_diff;
3966
3967 if (wait_count->total_count == 0)
3968 cur->status &=
3969 ~STATUS_WAIT_FOR_FRAME_ON_OTHER_LINKS;
3970 }
3971 }
3972 }
3973
3974 return QDF_STATUS_SUCCESS;
3975 }
3976
3977 static QDF_STATUS
mgmt_rx_reo_update_egress_list(struct mgmt_rx_reo_egress_list * egress_list,struct mgmt_rx_reo_frame_descriptor * frame_desc,struct mgmt_rx_reo_list_entry * new,bool * is_queued)3978 mgmt_rx_reo_update_egress_list(struct mgmt_rx_reo_egress_list *egress_list,
3979 struct mgmt_rx_reo_frame_descriptor *frame_desc,
3980 struct mgmt_rx_reo_list_entry *new,
3981 bool *is_queued)
3982 {
3983 struct mgmt_rx_reo_list *reo_egress_list;
3984 struct mgmt_rx_reo_list_entry *cur;
3985 struct mgmt_rx_reo_list_entry *last;
3986 struct mgmt_rx_reo_list_entry *least_greater = NULL;
3987 bool least_greater_entry_found = false;
3988 uint32_t ts_last;
3989 uint32_t ts_new;
3990 uint16_t list_insertion_pos = 0;
3991 QDF_STATUS ret;
3992
3993 if (!egress_list) {
3994 mgmt_rx_reo_err("Mgmt Rx reo egress list is null");
3995 return QDF_STATUS_E_NULL_VALUE;
3996 }
3997 reo_egress_list = &egress_list->reo_list;
3998
3999 if (!frame_desc) {
4000 mgmt_rx_reo_err("Mgmt frame descriptor is null");
4001 return QDF_STATUS_E_NULL_VALUE;
4002 }
4003
4004 if (!(frame_desc->type == MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME &&
4005 frame_desc->reo_required) != !new) {
4006 mgmt_rx_reo_err("Invalid input");
4007 return QDF_STATUS_E_INVAL;
4008 }
4009
4010 if (!is_queued) {
4011 mgmt_rx_reo_err("Pointer to queued indication is null");
4012 return QDF_STATUS_E_NULL_VALUE;
4013 }
4014 *is_queued = false;
4015
4016 ts_new = mgmt_rx_reo_get_global_ts(frame_desc->rx_params);
4017 frame_desc->egress_list_size_rx = qdf_list_size(&reo_egress_list->list);
4018
4019 ret = mgmt_rx_reo_is_stale_frame(&reo_egress_list->last_released_frame,
4020 frame_desc);
4021 if (QDF_IS_STATUS_ERROR(ret))
4022 return ret;
4023
4024 if (frame_desc->is_stale) {
4025 ret = mgmt_rx_reo_handle_stale_frame(reo_egress_list,
4026 frame_desc);
4027 if (QDF_IS_STATUS_ERROR(ret))
4028 return ret;
4029
4030 qdf_list_for_each(&reo_egress_list->list, cur, node) {
4031 uint32_t ts_cur;
4032
4033 ts_cur = mgmt_rx_reo_get_global_ts(cur->rx_params);
4034
4035 if (!mgmt_rx_reo_compare_global_timestamps_gte(ts_new,
4036 ts_cur))
4037 break;
4038
4039 qdf_assert_always(cur->is_parallel_rx);
4040 }
4041
4042 return QDF_STATUS_SUCCESS;
4043 }
4044
4045 if (!new)
4046 return QDF_STATUS_SUCCESS;
4047
4048 if (qdf_list_empty(&reo_egress_list->list))
4049 return QDF_STATUS_SUCCESS;
4050
4051 last = qdf_list_last_entry(&reo_egress_list->list,
4052 struct mgmt_rx_reo_list_entry, node);
4053
4054 ts_last = mgmt_rx_reo_get_global_ts(last->rx_params);
4055
4056 if (mgmt_rx_reo_compare_global_timestamps_gte(ts_new, ts_last))
4057 return QDF_STATUS_SUCCESS;
4058
4059 qdf_list_for_each(&reo_egress_list->list, cur, node) {
4060 uint32_t ts_cur;
4061
4062 ts_cur = mgmt_rx_reo_get_global_ts(cur->rx_params);
4063
4064 if (!mgmt_rx_reo_compare_global_timestamps_gte(ts_new,
4065 ts_cur)) {
4066 least_greater = cur;
4067 least_greater_entry_found = true;
4068 break;
4069 }
4070
4071 list_insertion_pos++;
4072 }
4073
4074 if (!least_greater_entry_found) {
4075 mgmt_rx_reo_err("Lest greater entry not found");
4076 return QDF_STATUS_E_FAILURE;
4077 }
4078
4079 ret = mgmt_rx_reo_update_wait_count(&new->wait_count,
4080 &least_greater->wait_count);
4081
4082 if (QDF_IS_STATUS_ERROR(ret))
4083 return ret;
4084
4085 frame_desc->wait_count = new->wait_count;
4086
4087 if (new->wait_count.total_count == 0)
4088 new->status &= ~STATUS_WAIT_FOR_FRAME_ON_OTHER_LINKS;
4089
4090 new->egress_list_insertion_ts = qdf_get_log_timestamp();
4091 new->ingress_timestamp = frame_desc->ingress_timestamp;
4092 new->is_parallel_rx = frame_desc->is_parallel_rx;
4093 new->status |= STATUS_OLDER_THAN_READY_TO_DELIVER_FRAMES;
4094 frame_desc->egress_list_insertion_pos = list_insertion_pos;
4095
4096 ret = qdf_list_insert_before(&reo_egress_list->list, &new->node,
4097 &least_greater->node);
4098 if (QDF_IS_STATUS_ERROR(ret))
4099 return ret;
4100
4101 if (mgmt_rx_reo_list_overflowed(reo_egress_list)) {
4102 ret = mgmt_rx_reo_handle_egress_overflow(reo_egress_list);
4103 if (QDF_IS_STATUS_ERROR(ret)) {
4104 mgmt_rx_reo_err("Failed to handle egress overflow");
4105 }
4106 }
4107
4108 *is_queued = true;
4109 frame_desc->queued_list = MGMT_RX_REO_LIST_TYPE_EGRESS;
4110
4111 if (frame_desc->wait_count.total_count == 0)
4112 frame_desc->zero_wait_count_rx = true;
4113 frame_desc->immediate_delivery = true;
4114
4115 return QDF_STATUS_SUCCESS;
4116 }
4117
4118 static QDF_STATUS
mgmt_rx_reo_update_lists(struct mgmt_rx_reo_ingress_list * ingress_list,struct mgmt_rx_reo_egress_list * egress_list,struct mgmt_rx_reo_frame_descriptor * frame_desc,bool * is_queued)4119 mgmt_rx_reo_update_lists(struct mgmt_rx_reo_ingress_list *ingress_list,
4120 struct mgmt_rx_reo_egress_list *egress_list,
4121 struct mgmt_rx_reo_frame_descriptor *frame_desc,
4122 bool *is_queued)
4123 {
4124 struct mgmt_rx_reo_list *reo_ingress_list;
4125 struct mgmt_rx_reo_list *reo_egress_list;
4126 bool is_queued_to_ingress_list = false;
4127 bool is_queued_to_egress_list = false;
4128 QDF_STATUS status;
4129 struct mgmt_rx_reo_list_entry *new_entry = NULL;
4130 enum mgmt_rx_reo_list_type queued_list;
4131
4132 if (!ingress_list) {
4133 mgmt_rx_reo_err("Mgmt Rx reo ingress list is null");
4134 return QDF_STATUS_E_NULL_VALUE;
4135 }
4136 reo_ingress_list = &ingress_list->reo_list;
4137
4138 if (!egress_list) {
4139 mgmt_rx_reo_err("Mgmt Rx reo egress list is null");
4140 return QDF_STATUS_E_NULL_VALUE;
4141 }
4142 reo_egress_list = &egress_list->reo_list;
4143
4144 if (!frame_desc) {
4145 mgmt_rx_reo_err("Mgmt frame descriptor is null");
4146 return QDF_STATUS_E_NULL_VALUE;
4147 }
4148
4149 if (!is_queued) {
4150 mgmt_rx_reo_err("Pointer to queued indication is null");
4151 return QDF_STATUS_E_NULL_VALUE;
4152 }
4153 *is_queued = false;
4154
4155 /* Prepare the list entry before acquiring lock */
4156 if (frame_desc->type == MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME &&
4157 frame_desc->reo_required) {
4158 status = mgmt_rx_reo_prepare_list_entry(frame_desc, &new_entry);
4159 if (QDF_IS_STATUS_ERROR(status)) {
4160 mgmt_rx_reo_err("Failed to prepare list entry");
4161 return QDF_STATUS_E_FAILURE;
4162 }
4163 }
4164
4165 qdf_spin_lock_bh(&reo_ingress_list->list_lock);
4166
4167 qdf_spin_lock_bh(&reo_egress_list->list_lock);
4168
4169 status = mgmt_rx_reo_update_egress_list(egress_list, frame_desc,
4170 new_entry,
4171 &is_queued_to_egress_list);
4172 if (QDF_IS_STATUS_ERROR(status)) {
4173 mgmt_rx_reo_err("Egress list update failed");
4174 goto exit_release_egress_list_lock;
4175 }
4176
4177 status = mgmt_rx_reo_check_sanity_list(reo_egress_list);
4178 if (QDF_IS_STATUS_ERROR(status)) {
4179 mgmt_rx_reo_err("Sanity check of egress list failed");
4180 goto exit_release_egress_list_lock;
4181 }
4182
4183 qdf_spin_unlock_bh(&reo_egress_list->list_lock);
4184
4185 status = mgmt_rx_reo_update_ingress_list(ingress_list, frame_desc,
4186 new_entry,
4187 &is_queued_to_ingress_list);
4188 if (QDF_IS_STATUS_ERROR(status)) {
4189 mgmt_rx_reo_err("Ingress list update failed");
4190 goto exit_release_ingress_list_lock;
4191 }
4192
4193 status = mgmt_rx_reo_check_sanity_list(reo_ingress_list);
4194 if (QDF_IS_STATUS_ERROR(status)) {
4195 mgmt_rx_reo_err("Sanity check of ingress list failed");
4196 goto exit_release_ingress_list_lock;
4197 }
4198
4199 status = QDF_STATUS_SUCCESS;
4200 goto exit_release_ingress_list_lock;
4201
4202 exit_release_egress_list_lock:
4203 qdf_spin_unlock_bh(&reo_egress_list->list_lock);
4204 exit_release_ingress_list_lock:
4205 qdf_spin_unlock_bh(&reo_ingress_list->list_lock);
4206
4207 if (is_queued_to_ingress_list && is_queued_to_egress_list)
4208 mgmt_rx_reo_err("Frame is queued to ingress and egress lists");
4209
4210 *is_queued = is_queued_to_ingress_list || is_queued_to_egress_list;
4211
4212 queued_list = frame_desc->queued_list;
4213 if (*is_queued && queued_list == MGMT_RX_REO_LIST_TYPE_INVALID)
4214 mgmt_rx_reo_err("Invalid queued list type %d", queued_list);
4215
4216 if (!new_entry && *is_queued)
4217 mgmt_rx_reo_err("Queued an invalid frame");
4218
4219 /* Cleanup the entry if it is not queued */
4220 if (new_entry && !*is_queued) {
4221 /**
4222 * New entry created is not inserted to reorder list, free
4223 * the entry and release the reference
4224 */
4225 wlan_objmgr_pdev_release_ref(new_entry->pdev,
4226 WLAN_MGMT_RX_REO_ID);
4227 qdf_mem_free(new_entry);
4228 }
4229
4230 return status;
4231 }
4232
4233 /**
4234 * mgmt_rx_reo_ingress_list_init() - Initialize the management rx-reorder
4235 * ingress list
4236 * @ingress_list: Pointer to ingress list
4237 *
4238 * API to initialize the management rx-reorder ingress list.
4239 *
4240 * Return: QDF_STATUS
4241 */
4242 static QDF_STATUS
mgmt_rx_reo_ingress_list_init(struct mgmt_rx_reo_ingress_list * ingress_list)4243 mgmt_rx_reo_ingress_list_init(struct mgmt_rx_reo_ingress_list *ingress_list)
4244 {
4245 QDF_STATUS status;
4246 struct mgmt_rx_reo_list *reo_ingress_list;
4247
4248 if (!ingress_list) {
4249 mgmt_rx_reo_err("Ingress list is null");
4250 return QDF_STATUS_E_NULL_VALUE;
4251 }
4252
4253 reo_ingress_list = &ingress_list->reo_list;
4254
4255 reo_ingress_list->max_list_size = MGMT_RX_REO_INGRESS_LIST_MAX_SIZE;
4256 qdf_list_create(&reo_ingress_list->list,
4257 reo_ingress_list->max_list_size);
4258 qdf_spinlock_create(&reo_ingress_list->list_lock);
4259 qdf_mem_zero(&reo_ingress_list->last_inserted_frame,
4260 sizeof(reo_ingress_list->last_inserted_frame));
4261 qdf_mem_zero(&reo_ingress_list->last_released_frame,
4262 sizeof(reo_ingress_list->last_released_frame));
4263
4264 ingress_list->list_entry_timeout_us =
4265 MGMT_RX_REO_INGRESS_LIST_TIMEOUT_US;
4266
4267 status = qdf_timer_init(NULL, &ingress_list->ageout_timer,
4268 mgmt_rx_reo_ingress_list_ageout_timer_handler,
4269 ingress_list, QDF_TIMER_TYPE_WAKE_APPS);
4270 if (QDF_IS_STATUS_ERROR(status)) {
4271 mgmt_rx_reo_err("Failed to initialize ingress ageout timer");
4272 return status;
4273 }
4274 qdf_timer_start(&ingress_list->ageout_timer,
4275 MGMT_RX_REO_INGRESS_LIST_AGEOUT_TIMER_PERIOD_MS);
4276
4277 return QDF_STATUS_SUCCESS;
4278 }
4279
4280 /**
4281 * mgmt_rx_reo_egress_list_init() - Initialize the management rx-reorder
4282 * egress list
4283 * @egress_list: Pointer to egress list
4284 *
4285 * API to initialize the management rx-reorder egress list.
4286 *
4287 * Return: QDF_STATUS
4288 */
4289 static QDF_STATUS
mgmt_rx_reo_egress_list_init(struct mgmt_rx_reo_egress_list * egress_list)4290 mgmt_rx_reo_egress_list_init(struct mgmt_rx_reo_egress_list *egress_list)
4291 {
4292 struct mgmt_rx_reo_list *reo_egress_list;
4293 QDF_STATUS status;
4294
4295 if (!egress_list) {
4296 mgmt_rx_reo_err("Egress list is null");
4297 return QDF_STATUS_E_NULL_VALUE;
4298 }
4299
4300 reo_egress_list = &egress_list->reo_list;
4301
4302 reo_egress_list->max_list_size = MGMT_RX_REO_EGRESS_LIST_MAX_SIZE;
4303 qdf_list_create(&reo_egress_list->list, reo_egress_list->max_list_size);
4304 qdf_spinlock_create(&reo_egress_list->list_lock);
4305 qdf_mem_zero(&reo_egress_list->last_inserted_frame,
4306 sizeof(reo_egress_list->last_inserted_frame));
4307 qdf_mem_zero(&reo_egress_list->last_released_frame,
4308 sizeof(reo_egress_list->last_released_frame));
4309
4310 status = qdf_timer_init(NULL, &egress_list->egress_inactivity_timer,
4311 mgmt_rx_reo_egress_inactivity_timer_handler,
4312 egress_list, QDF_TIMER_TYPE_WAKE_APPS);
4313 if (QDF_IS_STATUS_ERROR(status)) {
4314 mgmt_rx_reo_err("Failed to initialize egress inactivity timer");
4315 return status;
4316 }
4317
4318 return QDF_STATUS_SUCCESS;
4319 }
4320
4321 /**
4322 * check_frame_sanity() - Check the sanity of a given management frame
4323 * @pdev: Pointer to pdev object
4324 * @desc: Pointer to frame descriptor
4325 *
4326 * API to check the sanity of a given management frame. This API checks for the
4327 * following errors.
4328 *
4329 * 1. Invalid management rx reo parameters
4330 * 2. Host consumed management frames with zero duration
4331 *
4332 * Return: QDF_STATUS
4333 */
4334 static QDF_STATUS
check_frame_sanity(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_frame_descriptor * desc)4335 check_frame_sanity(struct wlan_objmgr_pdev *pdev,
4336 struct mgmt_rx_reo_frame_descriptor *desc)
4337 {
4338 QDF_STATUS status;
4339
4340 if (!desc) {
4341 mgmt_rx_reo_err("Frame descriptor is null");
4342 return QDF_STATUS_E_NULL_VALUE;
4343 }
4344
4345 status = check_and_handle_invalid_reo_params(desc);
4346 if (QDF_IS_STATUS_ERROR(status)) {
4347 mgmt_rx_reo_warn_rl("Drop frame with invalid reo params");
4348 return status;
4349 }
4350
4351 status = check_and_handle_zero_frame_duration(pdev, desc);
4352 if (QDF_IS_STATUS_ERROR(status)) {
4353 mgmt_rx_reo_warn_rl("Drop frame with zero duration");
4354 return status;
4355 }
4356
4357 return QDF_STATUS_SUCCESS;
4358 }
4359
4360 /**
4361 * wlan_mgmt_rx_reo_update_host_snapshot() - Update Host snapshot with the MGMT
4362 * Rx REO parameters.
4363 * @pdev: pdev extracted from the WMI event
4364 * @desc: pointer to frame descriptor
4365 *
4366 * Return: QDF_STATUS of operation
4367 */
4368 static QDF_STATUS
wlan_mgmt_rx_reo_update_host_snapshot(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_frame_descriptor * desc)4369 wlan_mgmt_rx_reo_update_host_snapshot(struct wlan_objmgr_pdev *pdev,
4370 struct mgmt_rx_reo_frame_descriptor *desc)
4371 {
4372 struct mgmt_rx_reo_pdev_info *rx_reo_pdev_ctx;
4373 struct mgmt_rx_reo_snapshot_params *host_ss;
4374 struct mgmt_rx_reo_params *reo_params;
4375 int pkt_ctr_delta;
4376 struct wlan_objmgr_psoc *psoc;
4377 uint16_t pkt_ctr_delta_thresh;
4378
4379 if (!desc) {
4380 mgmt_rx_reo_err("Mgmt Rx REO frame descriptor null");
4381 return QDF_STATUS_E_NULL_VALUE;
4382 }
4383
4384 if (!desc->rx_params) {
4385 mgmt_rx_reo_err("Mgmt Rx params null");
4386 return QDF_STATUS_E_NULL_VALUE;
4387 }
4388
4389 reo_params = desc->rx_params->reo_params;
4390 if (!reo_params) {
4391 mgmt_rx_reo_err("Mgmt Rx REO params NULL");
4392 return QDF_STATUS_E_NULL_VALUE;
4393 }
4394
4395 rx_reo_pdev_ctx = wlan_mgmt_rx_reo_get_priv_object(pdev);
4396 if (!rx_reo_pdev_ctx) {
4397 mgmt_rx_reo_err("Mgmt Rx REO context empty for pdev %pK", pdev);
4398 return QDF_STATUS_E_FAILURE;
4399 }
4400
4401 psoc = wlan_pdev_get_psoc(pdev);
4402
4403 /* FW should send valid REO parameters */
4404 if (!reo_params->valid) {
4405 mgmt_rx_reo_err("Mgmt Rx REO params is invalid");
4406 return QDF_STATUS_E_FAILURE;
4407 }
4408
4409 host_ss = &rx_reo_pdev_ctx->host_snapshot;
4410
4411 if (!host_ss->valid) {
4412 desc->pkt_ctr_delta = 1;
4413 goto update_host_ss;
4414 }
4415
4416 if (mgmt_rx_reo_compare_pkt_ctrs_gte(host_ss->mgmt_pkt_ctr,
4417 reo_params->mgmt_pkt_ctr)) {
4418 QDF_STATUS status;
4419
4420 status = handle_out_of_order_pkt_ctr(desc, host_ss);
4421 if (QDF_IS_STATUS_ERROR(status)) {
4422 mgmt_rx_reo_err_rl("Failed to handle out of order pkt");
4423 goto failure_debug;
4424 }
4425
4426 mgmt_rx_reo_warn_rl("Drop frame with out of order pkt ctr");
4427 }
4428
4429 pkt_ctr_delta = mgmt_rx_reo_subtract_pkt_ctrs(reo_params->mgmt_pkt_ctr,
4430 host_ss->mgmt_pkt_ctr);
4431 desc->pkt_ctr_delta = pkt_ctr_delta;
4432
4433 if (pkt_ctr_delta == 1)
4434 goto update_host_ss;
4435
4436 /*
4437 * Under back pressure scenarios, FW may drop management Rx frame
4438 * WMI events. So holes in the management packet counter is expected.
4439 * Add a debug print and optional assert to track the holes.
4440 */
4441 mgmt_rx_reo_debug("pkt_ctr_delta = %d, link = %u", pkt_ctr_delta,
4442 reo_params->link_id);
4443 mgmt_rx_reo_debug("Cur frame valid = %u, pkt_ctr = %u, ts = %u",
4444 reo_params->valid, reo_params->mgmt_pkt_ctr,
4445 reo_params->global_timestamp);
4446 mgmt_rx_reo_debug("Last frame valid = %u, pkt_ctr = %u, ts = %u",
4447 host_ss->valid, host_ss->mgmt_pkt_ctr,
4448 host_ss->global_timestamp);
4449
4450 pkt_ctr_delta_thresh = wlan_mgmt_rx_reo_get_pkt_ctr_delta_thresh(psoc);
4451
4452 if (pkt_ctr_delta_thresh && pkt_ctr_delta > pkt_ctr_delta_thresh) {
4453 mgmt_rx_reo_err("pkt ctr delta %u > thresh %u for link %u",
4454 pkt_ctr_delta, pkt_ctr_delta_thresh,
4455 reo_params->link_id);
4456 goto failure_debug;
4457 }
4458
4459 update_host_ss:
4460 host_ss->valid = true;
4461 host_ss->global_timestamp = reo_params->global_timestamp;
4462 host_ss->mgmt_pkt_ctr = reo_params->mgmt_pkt_ctr;
4463
4464 return QDF_STATUS_SUCCESS;
4465
4466 failure_debug:
4467 mgmt_rx_reo_err("Cur Pkt valid = %u, pkt_ctr = %u, ts = %u, link = %u",
4468 reo_params->valid, reo_params->mgmt_pkt_ctr,
4469 reo_params->global_timestamp, reo_params->link_id);
4470 mgmt_rx_reo_err("Last Pkt valid = %u, pkt_ctr = %u, ts = %u",
4471 host_ss->valid, host_ss->mgmt_pkt_ctr,
4472 host_ss->global_timestamp);
4473 mgmt_rx_reo_err("Triggering self recovery, out of order pkt");
4474 qdf_trigger_self_recovery(psoc, QDF_MGMT_RX_REO_OUT_OF_ORDER_PKT);
4475
4476 return QDF_STATUS_E_FAILURE;
4477 }
4478
4479 #ifdef WLAN_MGMT_RX_REO_DEBUG_SUPPORT
4480 /**
4481 * mgmt_rx_reo_ingress_frame_debug_info_enabled() - API to check whether ingress
4482 * frame info debug feaure is enabled
4483 * @ingress_frame_debug_info: Pointer to ingress frame debug info object
4484 *
4485 * Return: true or false
4486 */
4487 static bool
mgmt_rx_reo_ingress_frame_debug_info_enabled(struct reo_ingress_debug_info * ingress_frame_debug_info)4488 mgmt_rx_reo_ingress_frame_debug_info_enabled
4489 (struct reo_ingress_debug_info *ingress_frame_debug_info)
4490 {
4491 return ingress_frame_debug_info->frame_list_size;
4492 }
4493
4494 /**
4495 * mgmt_rx_reo_debug_print_ingress_frame_stats() - API to print the stats
4496 * related to frames going into the reorder module
4497 * @reo_ctx: Pointer to reorder context
4498 *
4499 * API to print the stats related to frames going into the management
4500 * Rx reorder module.
4501 *
4502 * Return: QDF_STATUS
4503 */
4504 static QDF_STATUS
mgmt_rx_reo_debug_print_ingress_frame_stats(struct mgmt_rx_reo_context * reo_ctx)4505 mgmt_rx_reo_debug_print_ingress_frame_stats(struct mgmt_rx_reo_context *reo_ctx)
4506 {
4507 struct reo_ingress_frame_stats *stats;
4508 uint8_t link_id;
4509 uint8_t desc_type;
4510 uint8_t reason;
4511 uint8_t list_type;
4512 uint64_t ingress_count_per_link[MAX_MLO_LINKS] = {0};
4513 uint64_t ingress_count_per_desc_type[MGMT_RX_REO_FRAME_DESC_TYPE_MAX] = {0};
4514 uint64_t total_ingress_count = 0;
4515 uint64_t reo_count_per_link[MAX_MLO_LINKS] = {0};
4516 uint64_t reo_count_per_desc_type[MGMT_RX_REO_FRAME_DESC_TYPE_MAX] = {0};
4517 uint64_t total_reo_count = 0;
4518 uint64_t stale_count_per_link[MAX_MLO_LINKS] = {0};
4519 uint64_t stale_count_per_desc_type[MGMT_RX_REO_FRAME_DESC_TYPE_MAX] = {0};
4520 uint64_t total_stale_count = 0;
4521 uint64_t parallel_rx_count_per_link[MAX_MLO_LINKS] = {0};
4522 uint64_t parallel_rx_per_desc[MGMT_RX_REO_FRAME_DESC_TYPE_MAX] = {0};
4523 uint64_t total_parallel_rx_count = 0;
4524 uint64_t error_count_per_link[MAX_MLO_LINKS] = {0};
4525 uint64_t error_count_per_desc_type[MGMT_RX_REO_FRAME_DESC_TYPE_MAX] = {0};
4526 uint64_t total_error_count = 0;
4527 uint64_t drop_count_per_link[MAX_MLO_LINKS] = {0};
4528 uint64_t drop_count_per_reason[MGMT_RX_REO_INGRESS_DROP_REASON_MAX] = {0};
4529 uint64_t total_drop_count = 0;
4530 uint64_t total_missing_count = 0;
4531 uint64_t total_queued = 0;
4532 uint64_t queued_per_list[MGMT_RX_REO_LIST_TYPE_MAX] = {0};
4533 uint64_t queued_per_link[MAX_MLO_LINKS] = {0};
4534 uint64_t total_zero_wait_count_rx = 0;
4535 uint64_t zero_wait_count_rx_per_list[MGMT_RX_REO_LIST_TYPE_MAX] = {0};
4536 uint64_t zero_wait_count_rx_per_link[MAX_MLO_LINKS] = {0};
4537 uint64_t total_immediate_delivery = 0;
4538 uint64_t immediate_delivery_per_list[MGMT_RX_REO_LIST_TYPE_MAX] = {0};
4539 uint64_t immediate_delivery_per_link[MAX_MLO_LINKS] = {0};
4540
4541 if (!reo_ctx)
4542 return QDF_STATUS_E_NULL_VALUE;
4543
4544 stats = &reo_ctx->ingress_frame_debug_info.stats;
4545
4546 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4547 for (desc_type = 0; desc_type < MGMT_RX_REO_FRAME_DESC_TYPE_MAX;
4548 desc_type++) {
4549 ingress_count_per_link[link_id] +=
4550 stats->ingress_count[link_id][desc_type];
4551 reo_count_per_link[link_id] +=
4552 stats->reo_count[link_id][desc_type];
4553 stale_count_per_link[link_id] +=
4554 stats->stale_count[link_id][desc_type];
4555 error_count_per_link[link_id] +=
4556 stats->error_count[link_id][desc_type];
4557 parallel_rx_count_per_link[link_id] +=
4558 stats->parallel_rx_count[link_id][desc_type];
4559 }
4560
4561 total_ingress_count += ingress_count_per_link[link_id];
4562 total_reo_count += reo_count_per_link[link_id];
4563 total_stale_count += stale_count_per_link[link_id];
4564 total_error_count += error_count_per_link[link_id];
4565 total_parallel_rx_count += parallel_rx_count_per_link[link_id];
4566 total_missing_count += stats->missing_count[link_id];
4567 }
4568
4569 for (desc_type = 0; desc_type < MGMT_RX_REO_FRAME_DESC_TYPE_MAX;
4570 desc_type++) {
4571 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4572 ingress_count_per_desc_type[desc_type] +=
4573 stats->ingress_count[link_id][desc_type];
4574 reo_count_per_desc_type[desc_type] +=
4575 stats->reo_count[link_id][desc_type];
4576 stale_count_per_desc_type[desc_type] +=
4577 stats->stale_count[link_id][desc_type];
4578 error_count_per_desc_type[desc_type] +=
4579 stats->error_count[link_id][desc_type];
4580 parallel_rx_per_desc[desc_type] +=
4581 stats->parallel_rx_count[link_id][desc_type];
4582 }
4583 }
4584
4585 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4586 for (list_type = 0; list_type < MGMT_RX_REO_LIST_TYPE_MAX;
4587 list_type++) {
4588 queued_per_link[link_id] +=
4589 stats->queued_count[link_id][list_type];
4590 zero_wait_count_rx_per_link[link_id] +=
4591 stats->zero_wait_count_rx_count[link_id][list_type];
4592 immediate_delivery_per_link[link_id] +=
4593 stats->immediate_delivery_count[link_id][list_type];
4594 }
4595
4596 total_queued += queued_per_link[link_id];
4597 total_zero_wait_count_rx +=
4598 zero_wait_count_rx_per_link[link_id];
4599 total_immediate_delivery +=
4600 immediate_delivery_per_link[link_id];
4601 }
4602
4603 for (list_type = 0; list_type < MGMT_RX_REO_LIST_TYPE_MAX;
4604 list_type++) {
4605 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4606 queued_per_list[list_type] +=
4607 stats->queued_count[link_id][list_type];
4608 zero_wait_count_rx_per_list[list_type] +=
4609 stats->zero_wait_count_rx_count[link_id][list_type];
4610 immediate_delivery_per_list[list_type] +=
4611 stats->immediate_delivery_count[link_id][list_type];
4612 }
4613 }
4614
4615 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4616 for (reason = 0; reason < MGMT_RX_REO_INGRESS_DROP_REASON_MAX;
4617 reason++) {
4618 drop_count_per_link[link_id] +=
4619 stats->drop_count[link_id][reason];
4620 }
4621 total_drop_count += drop_count_per_link[link_id];
4622 }
4623
4624 for (reason = 0; reason < MGMT_RX_REO_INGRESS_DROP_REASON_MAX;
4625 reason++) {
4626 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4627 drop_count_per_reason[reason] +=
4628 stats->drop_count[link_id][reason];
4629 }
4630 }
4631
4632 mgmt_rx_reo_alert("Ingress Frame Stats:");
4633 mgmt_rx_reo_alert("\t1) Ingress Frame Count:");
4634 mgmt_rx_reo_alert("\tDescriptor Type Values:-");
4635 mgmt_rx_reo_alert("\t\t0 - MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME");
4636 mgmt_rx_reo_alert("\t\t1 - MGMT_RX_REO_FRAME_DESC_FW_CONSUMED_FRAME");
4637 mgmt_rx_reo_alert("\t\t2 - MGMT_RX_REO_FRAME_DESC_ERROR_FRAME");
4638 mgmt_rx_reo_alert("\t------------------------------------");
4639 mgmt_rx_reo_alert("\t|link id/ | | | |");
4640 mgmt_rx_reo_alert("\t|desc type | 0| 1| 2|");
4641 mgmt_rx_reo_alert("\t-------------------------------------------");
4642
4643 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4644 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
4645 stats->ingress_count[link_id][0],
4646 stats->ingress_count[link_id][1],
4647 stats->ingress_count[link_id][2],
4648 ingress_count_per_link[link_id]);
4649 mgmt_rx_reo_alert("\t-------------------------------------------");
4650 }
4651 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
4652 ingress_count_per_desc_type[0],
4653 ingress_count_per_desc_type[1],
4654 ingress_count_per_desc_type[2],
4655 total_ingress_count);
4656
4657 mgmt_rx_reo_alert("\t2) Reo required Frame Count:");
4658 mgmt_rx_reo_alert("\t------------------------------------");
4659 mgmt_rx_reo_alert("\t|link id/ | | | |");
4660 mgmt_rx_reo_alert("\t|desc type | 0| 1| 2|");
4661 mgmt_rx_reo_alert("\t-------------------------------------------");
4662
4663 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4664 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
4665 stats->reo_count[link_id][0],
4666 stats->reo_count[link_id][1],
4667 stats->reo_count[link_id][2],
4668 reo_count_per_link[link_id]);
4669 mgmt_rx_reo_alert("\t-------------------------------------------");
4670 }
4671 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
4672 reo_count_per_desc_type[0],
4673 reo_count_per_desc_type[1],
4674 reo_count_per_desc_type[2],
4675 total_reo_count);
4676
4677 mgmt_rx_reo_alert("\t3) Stale Frame Count:");
4678 mgmt_rx_reo_alert("\t------------------------------------");
4679 mgmt_rx_reo_alert("\t|link id/ | | | |");
4680 mgmt_rx_reo_alert("\t|desc type | 0| 1| 2|");
4681 mgmt_rx_reo_alert("\t-------------------------------------------");
4682 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4683 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
4684 stats->stale_count[link_id][0],
4685 stats->stale_count[link_id][1],
4686 stats->stale_count[link_id][2],
4687 stale_count_per_link[link_id]);
4688 mgmt_rx_reo_alert("\t-------------------------------------------");
4689 }
4690 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
4691 stale_count_per_desc_type[0],
4692 stale_count_per_desc_type[1],
4693 stale_count_per_desc_type[2],
4694 total_stale_count);
4695
4696 mgmt_rx_reo_alert("\t4) Parallel rx Frame Count:");
4697 mgmt_rx_reo_alert("\t------------------------------------");
4698 mgmt_rx_reo_alert("\t|link id/ | | | |");
4699 mgmt_rx_reo_alert("\t|desc type | 0| 1| 2|");
4700 mgmt_rx_reo_alert("\t-------------------------------------------");
4701 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4702 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
4703 stats->parallel_rx_count[link_id][0],
4704 stats->parallel_rx_count[link_id][1],
4705 stats->parallel_rx_count[link_id][2],
4706 parallel_rx_count_per_link[link_id]);
4707 mgmt_rx_reo_alert("\t-------------------------------------------");
4708 }
4709 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
4710 parallel_rx_per_desc[0], parallel_rx_per_desc[1],
4711 parallel_rx_per_desc[2], total_parallel_rx_count);
4712
4713 mgmt_rx_reo_alert("\t5) Error Frame Count:");
4714 mgmt_rx_reo_alert("\t------------------------------------");
4715 mgmt_rx_reo_alert("\t|link id/ | | | |");
4716 mgmt_rx_reo_alert("\t|desc type | 0| 1| 2|");
4717 mgmt_rx_reo_alert("\t-------------------------------------------");
4718 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4719 mgmt_rx_reo_alert("\t|%10u|%7llu|%7llu|%7llu|%7llu", link_id,
4720 stats->error_count[link_id][0],
4721 stats->error_count[link_id][1],
4722 stats->error_count[link_id][2],
4723 error_count_per_link[link_id]);
4724 mgmt_rx_reo_alert("\t-------------------------------------------");
4725 }
4726 mgmt_rx_reo_alert("\t |%7llu|%7llu|%7llu|%7llu\n\n",
4727 error_count_per_desc_type[0],
4728 error_count_per_desc_type[1],
4729 error_count_per_desc_type[2],
4730 total_error_count);
4731
4732 mgmt_rx_reo_alert("\t6) Drop Frame Count:");
4733 mgmt_rx_reo_alert("\t--------------------------------------------");
4734 mgmt_rx_reo_alert("\t|link/| | | | | | |");
4735 mgmt_rx_reo_alert("\t|reas.| 0| 1| 2| 3| 4| 5|");
4736 mgmt_rx_reo_alert("\t--------------------------------------------");
4737 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4738 mgmt_rx_reo_alert("\t|%5u|%4llu|%4llu|%4llu|%4llu|%4llu|%4llu|%7llu",
4739 link_id, stats->drop_count[link_id][0],
4740 stats->drop_count[link_id][1],
4741 stats->drop_count[link_id][2],
4742 stats->drop_count[link_id][3],
4743 stats->drop_count[link_id][4],
4744 stats->drop_count[link_id][5],
4745 drop_count_per_link[link_id]);
4746 mgmt_rx_reo_alert("\t--------------------------------------------");
4747 }
4748 mgmt_rx_reo_alert("\t%6s|%4llu|%4llu|%4llu|%4llu|%4llu|%4llu|%7llu\n\n",
4749 "", drop_count_per_reason[0],
4750 drop_count_per_reason[1], drop_count_per_reason[2],
4751 drop_count_per_reason[3], drop_count_per_reason[4],
4752 drop_count_per_reason[5], total_drop_count);
4753
4754 mgmt_rx_reo_alert("\t7) Per link stats:");
4755 mgmt_rx_reo_alert("\t----------------------------");
4756 mgmt_rx_reo_alert("\t|link id | Missing frame |");
4757 mgmt_rx_reo_alert("\t| | count |");
4758 mgmt_rx_reo_alert("\t----------------------------");
4759 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4760 mgmt_rx_reo_alert("\t|%10u|%15llu|", link_id,
4761 stats->missing_count[link_id]);
4762 mgmt_rx_reo_alert("\t----------------------------");
4763 }
4764 mgmt_rx_reo_alert("\t%11s|%15llu|\n\n", "", total_missing_count);
4765
4766 mgmt_rx_reo_alert("\t8) Host consumed frames related stats:");
4767 mgmt_rx_reo_alert("\tOverall:");
4768 mgmt_rx_reo_alert("\t------------------------------------------------");
4769 mgmt_rx_reo_alert("\t|link id |Queued frame |Zero wait |Immediate |");
4770 mgmt_rx_reo_alert("\t| | count | count | delivery |");
4771 mgmt_rx_reo_alert("\t------------------------------------------------");
4772 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4773 mgmt_rx_reo_alert("\t|%10u|%13llu|%10llu|%10llu|", link_id,
4774 queued_per_link[link_id],
4775 zero_wait_count_rx_per_link[link_id],
4776 immediate_delivery_per_link[link_id]);
4777 mgmt_rx_reo_alert("\t------------------------------------------------");
4778 }
4779 mgmt_rx_reo_alert("\t%11s|%13llu|%10llu|%10llu|\n\n", "",
4780 total_queued,
4781 total_zero_wait_count_rx,
4782 total_immediate_delivery);
4783
4784 mgmt_rx_reo_alert("\t\ta) Ingress List:");
4785 mgmt_rx_reo_alert("\t\t------------------------------------------------");
4786 mgmt_rx_reo_alert("\t\t|link id |Queued frame |Zero wait |Immediate |");
4787 mgmt_rx_reo_alert("\t\t| | count | count | delivery |");
4788 mgmt_rx_reo_alert("\t\t------------------------------------------------");
4789 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4790 mgmt_rx_reo_alert("\t\t|%10u|%13llu|%10llu|%10llu|", link_id,
4791 stats->queued_count[link_id][0],
4792 stats->zero_wait_count_rx_count[link_id][0],
4793 stats->immediate_delivery_count[link_id][0]);
4794 mgmt_rx_reo_alert("\t\t------------------------------------------------");
4795 }
4796 mgmt_rx_reo_alert("\t\t%11s|%13llu|%10llu|%10llu|\n\n", "",
4797 queued_per_list[0],
4798 zero_wait_count_rx_per_list[0],
4799 immediate_delivery_per_list[0]);
4800
4801 mgmt_rx_reo_alert("\t\tb) Egress List:");
4802 mgmt_rx_reo_alert("\t\t------------------------------------------------");
4803 mgmt_rx_reo_alert("\t\t|link id |Queued frame |Zero wait |Immediate |");
4804 mgmt_rx_reo_alert("\t\t| | count | count | delivery |");
4805 mgmt_rx_reo_alert("\t\t------------------------------------------------");
4806 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
4807 mgmt_rx_reo_alert("\t\t|%10u|%13llu|%10llu|%10llu|", link_id,
4808 stats->queued_count[link_id][1],
4809 stats->zero_wait_count_rx_count[link_id][1],
4810 stats->immediate_delivery_count[link_id][1]);
4811 mgmt_rx_reo_alert("\t\t------------------------------------------------");
4812 }
4813 mgmt_rx_reo_alert("\t\t%11s|%13llu|%10llu|%10llu|\n\n", "",
4814 queued_per_list[1],
4815 zero_wait_count_rx_per_list[1],
4816 immediate_delivery_per_list[1]);
4817
4818 mgmt_rx_reo_alert("\t9) Misc stats:");
4819 mgmt_rx_reo_alert("\t\tIngress list overflow count = %llu\n\n",
4820 reo_ctx->ingress_list.reo_list.overflow_count);
4821
4822 return QDF_STATUS_SUCCESS;
4823 }
4824
4825 /**
4826 * log_ingress_frame_entry() - Log the information about a frame at the start
4827 * of incoming frame processing
4828 * @reo_ctx: management rx reorder context
4829 * @desc: Pointer to frame descriptor
4830 *
4831 * Return: QDF_STATUS of operation
4832 */
4833 static QDF_STATUS
log_ingress_frame_entry(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_frame_descriptor * desc)4834 log_ingress_frame_entry(struct mgmt_rx_reo_context *reo_ctx,
4835 struct mgmt_rx_reo_frame_descriptor *desc)
4836 {
4837 struct reo_ingress_debug_info *ingress_frame_debug_info;
4838 struct reo_ingress_debug_frame_info *cur_frame_debug_info;
4839
4840 if (!reo_ctx || !desc)
4841 return QDF_STATUS_E_NULL_VALUE;
4842
4843 ingress_frame_debug_info = &reo_ctx->ingress_frame_debug_info;
4844
4845 if (!mgmt_rx_reo_ingress_frame_debug_info_enabled
4846 (ingress_frame_debug_info))
4847 return QDF_STATUS_SUCCESS;
4848
4849 cur_frame_debug_info = &ingress_frame_debug_info->frame_list
4850 [ingress_frame_debug_info->next_index];
4851
4852 cur_frame_debug_info->link_id =
4853 mgmt_rx_reo_get_link_id(desc->rx_params);
4854 cur_frame_debug_info->mgmt_pkt_ctr =
4855 mgmt_rx_reo_get_pkt_counter(desc->rx_params);
4856 cur_frame_debug_info->global_timestamp =
4857 mgmt_rx_reo_get_global_ts(desc->rx_params);
4858 cur_frame_debug_info->start_timestamp =
4859 mgmt_rx_reo_get_start_ts(desc->rx_params);
4860 cur_frame_debug_info->end_timestamp =
4861 mgmt_rx_reo_get_end_ts(desc->rx_params);
4862 cur_frame_debug_info->duration_us =
4863 mgmt_rx_reo_get_duration_us(desc->rx_params);
4864 cur_frame_debug_info->desc_type = desc->type;
4865 cur_frame_debug_info->frame_type = desc->frame_type;
4866 cur_frame_debug_info->frame_subtype = desc->frame_subtype;
4867 cur_frame_debug_info->cpu_id = qdf_get_smp_processor_id();
4868 cur_frame_debug_info->reo_required = desc->reo_required;
4869
4870 return QDF_STATUS_SUCCESS;
4871 }
4872
4873 /**
4874 * log_ingress_frame_exit() - Log the information about a frame at the end of
4875 * incoming frame processing
4876 * @reo_ctx: management rx reorder context
4877 * @desc: Pointer to frame descriptor
4878 * @is_queued: Indicates whether this frame is queued to reorder list
4879 * @is_error: Indicates whether any error occurred during processing this frame
4880 * @context_id: context identifier
4881 * @link_id: Link ID
4882 *
4883 * Return: QDF_STATUS of operation
4884 */
4885 static QDF_STATUS
log_ingress_frame_exit(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_frame_descriptor * desc,bool is_queued,bool is_error,int32_t context_id,uint8_t link_id)4886 log_ingress_frame_exit(struct mgmt_rx_reo_context *reo_ctx,
4887 struct mgmt_rx_reo_frame_descriptor *desc,
4888 bool is_queued, bool is_error,
4889 int32_t context_id, uint8_t link_id)
4890 {
4891 struct reo_ingress_debug_info *ingress_frame_debug_info;
4892 struct reo_ingress_debug_frame_info *cur_frame_debug_info;
4893 struct reo_ingress_frame_stats *stats;
4894 enum mgmt_rx_reo_list_type queued_list;
4895
4896 if (!reo_ctx || !desc)
4897 return QDF_STATUS_E_NULL_VALUE;
4898
4899 ingress_frame_debug_info = &reo_ctx->ingress_frame_debug_info;
4900
4901 stats = &ingress_frame_debug_info->stats;
4902 queued_list = desc->queued_list;
4903 stats->ingress_count[link_id][desc->type]++;
4904 if (desc->reo_required)
4905 stats->reo_count[link_id][desc->type]++;
4906 if (is_queued)
4907 stats->queued_count[link_id][queued_list]++;
4908 if (desc->zero_wait_count_rx)
4909 stats->zero_wait_count_rx_count[link_id][queued_list]++;
4910 if (desc->immediate_delivery)
4911 stats->immediate_delivery_count[link_id][queued_list]++;
4912 if (is_error)
4913 stats->error_count[link_id][desc->type]++;
4914 if (desc->is_stale)
4915 stats->stale_count[link_id][desc->type]++;
4916 if (desc->pkt_ctr_delta > 1)
4917 stats->missing_count[link_id] += desc->pkt_ctr_delta - 1;
4918 if (desc->is_parallel_rx)
4919 stats->parallel_rx_count[link_id][desc->type]++;
4920 if (desc->drop)
4921 stats->drop_count[link_id][desc->drop_reason]++;
4922
4923 if (!mgmt_rx_reo_ingress_frame_debug_info_enabled
4924 (ingress_frame_debug_info))
4925 return QDF_STATUS_SUCCESS;
4926
4927 cur_frame_debug_info = &ingress_frame_debug_info->frame_list
4928 [ingress_frame_debug_info->next_index];
4929
4930 cur_frame_debug_info->wait_count = desc->wait_count;
4931 qdf_mem_copy(cur_frame_debug_info->shared_snapshots,
4932 desc->shared_snapshots,
4933 qdf_min(sizeof(cur_frame_debug_info->shared_snapshots),
4934 sizeof(desc->shared_snapshots)));
4935 qdf_mem_copy(cur_frame_debug_info->host_snapshot, desc->host_snapshot,
4936 qdf_min(sizeof(cur_frame_debug_info->host_snapshot),
4937 sizeof(desc->host_snapshot)));
4938 cur_frame_debug_info->is_queued = is_queued;
4939 cur_frame_debug_info->is_stale = desc->is_stale;
4940 cur_frame_debug_info->is_parallel_rx = desc->is_parallel_rx;
4941 cur_frame_debug_info->queued_list = desc->queued_list;
4942 cur_frame_debug_info->zero_wait_count_rx = desc->zero_wait_count_rx;
4943 cur_frame_debug_info->immediate_delivery = desc->immediate_delivery;
4944 cur_frame_debug_info->is_error = is_error;
4945 cur_frame_debug_info->last_delivered_frame = desc->last_delivered_frame;
4946 cur_frame_debug_info->ingress_timestamp = desc->ingress_timestamp;
4947 cur_frame_debug_info->ingress_duration =
4948 qdf_get_log_timestamp() - desc->ingress_timestamp;
4949 cur_frame_debug_info->ingress_list_size_rx =
4950 desc->ingress_list_size_rx;
4951 cur_frame_debug_info->ingress_list_insertion_pos =
4952 desc->ingress_list_insertion_pos;
4953 cur_frame_debug_info->egress_list_size_rx =
4954 desc->egress_list_size_rx;
4955 cur_frame_debug_info->egress_list_insertion_pos =
4956 desc->egress_list_insertion_pos;
4957 cur_frame_debug_info->context_id = context_id;
4958 cur_frame_debug_info->drop = desc->drop;
4959 cur_frame_debug_info->drop_reason = desc->drop_reason;
4960
4961 ingress_frame_debug_info->next_index++;
4962 ingress_frame_debug_info->next_index %=
4963 ingress_frame_debug_info->frame_list_size;
4964 if (ingress_frame_debug_info->next_index == 0)
4965 ingress_frame_debug_info->wrap_aroud = true;
4966
4967 return QDF_STATUS_SUCCESS;
4968 }
4969
4970 /**
4971 * mgmt_rx_reo_debug_print_ingress_frame_info() - Print the debug information
4972 * about the latest frames entered the reorder module
4973 * @reo_ctx: management rx reorder context
4974 * @num_frames: Number of frames for which the debug information is to be
4975 * printed. If @num_frames is 0, then debug information about all the frames
4976 * in the ring buffer will be printed.
4977 *
4978 * Return: QDF_STATUS of operation
4979 */
4980 static QDF_STATUS
mgmt_rx_reo_debug_print_ingress_frame_info(struct mgmt_rx_reo_context * reo_ctx,uint16_t num_frames)4981 mgmt_rx_reo_debug_print_ingress_frame_info(struct mgmt_rx_reo_context *reo_ctx,
4982 uint16_t num_frames)
4983 {
4984 struct reo_ingress_debug_info *ingress_frame_debug_info;
4985 int start_index;
4986 uint16_t index;
4987 uint16_t entry;
4988 uint16_t num_valid_entries;
4989 uint16_t num_entries_to_print;
4990 char *boarder;
4991
4992 if (!reo_ctx)
4993 return QDF_STATUS_E_NULL_VALUE;
4994
4995 ingress_frame_debug_info = &reo_ctx->ingress_frame_debug_info;
4996
4997 if (ingress_frame_debug_info->wrap_aroud)
4998 num_valid_entries = ingress_frame_debug_info->frame_list_size;
4999 else
5000 num_valid_entries = ingress_frame_debug_info->next_index;
5001
5002 if (num_frames == 0) {
5003 num_entries_to_print = num_valid_entries;
5004
5005 if (ingress_frame_debug_info->wrap_aroud)
5006 start_index = ingress_frame_debug_info->next_index;
5007 else
5008 start_index = 0;
5009 } else {
5010 num_entries_to_print = qdf_min(num_frames, num_valid_entries);
5011
5012 start_index = (ingress_frame_debug_info->next_index -
5013 num_entries_to_print +
5014 ingress_frame_debug_info->frame_list_size)
5015 % ingress_frame_debug_info->frame_list_size;
5016 }
5017
5018 mgmt_rx_reo_alert_no_fl("Ingress Frame Info:-");
5019 mgmt_rx_reo_alert_no_fl("num_frames = %u, wrap = %u, next_index = %u",
5020 num_frames,
5021 ingress_frame_debug_info->wrap_aroud,
5022 ingress_frame_debug_info->next_index);
5023 mgmt_rx_reo_alert_no_fl("start_index = %d num_entries_to_print = %u",
5024 start_index, num_entries_to_print);
5025
5026 if (!num_entries_to_print)
5027 return QDF_STATUS_SUCCESS;
5028
5029 boarder = ingress_frame_debug_info->boarder;
5030
5031 mgmt_rx_reo_alert_no_fl("%s", boarder);
5032 mgmt_rx_reo_alert_no_fl("|%5s|%5s|%6s|%6s|%9s|%4s|%5s|%10s|%10s|%10s|%5s|%10s|%11s|%13s|%4s|%11s|%6s|%5s|%6s|%5s|%69s|%94s|%94s|%94s|%94s|%94s|%94s|",
5033 "Index", "CPU", "D.type", "F.type", "F.subtype",
5034 "Link", "SeqNo", "Global ts",
5035 "Start ts", "End ts", "Dur", "Last ts",
5036 "Ingress ts", "Flags", "List", "Ingress Dur",
5037 "I Size", "I Pos", "E Size",
5038 "E Pos", "Wait Count", "Snapshot : link 0",
5039 "Snapshot : link 1", "Snapshot : link 2",
5040 "Snapshot : link 3", "Snapshot : link 4",
5041 "Snapshot : link 5");
5042 mgmt_rx_reo_alert_no_fl("%s", boarder);
5043
5044 index = start_index;
5045 for (entry = 0; entry < num_entries_to_print; entry++) {
5046 struct reo_ingress_debug_frame_info *info;
5047 char flags[MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_FLAG_MAX_SIZE + 1] = {0};
5048 char wait_count[MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_WAIT_COUNT_MAX_SIZE + 1] = {0};
5049 char snapshots[MAX_MLO_LINKS][MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_PER_LINK_SNAPSHOTS_MAX_SIZE + 1] = {0};
5050 char flag_queued = ' ';
5051 char flag_stale = ' ';
5052 char flag_parallel_rx = ' ';
5053 char flag_error = ' ';
5054 char flag_zero_wait_count_rx = ' ';
5055 char flag_immediate_delivery = ' ';
5056 char flag_reo_required = ' ';
5057 int64_t ts_last_delivered_frame = -1;
5058 uint8_t link;
5059
5060 info = &reo_ctx->ingress_frame_debug_info.frame_list[index];
5061
5062 if (info->last_delivered_frame.valid) {
5063 struct mgmt_rx_reo_params *reo_params;
5064
5065 reo_params = &info->last_delivered_frame.reo_params;
5066 ts_last_delivered_frame = reo_params->global_timestamp;
5067 }
5068
5069 if (info->is_queued)
5070 flag_queued = 'Q';
5071
5072 if (info->is_stale)
5073 flag_stale = 'S';
5074
5075 if (info->is_parallel_rx)
5076 flag_parallel_rx = 'P';
5077
5078 if (info->is_error)
5079 flag_error = 'E';
5080
5081 if (info->zero_wait_count_rx)
5082 flag_zero_wait_count_rx = 'Z';
5083
5084 if (info->immediate_delivery)
5085 flag_immediate_delivery = 'I';
5086
5087 if (!info->reo_required)
5088 flag_reo_required = 'N';
5089
5090 snprintf(flags, sizeof(flags), "%c %c %c %c %c %c %c",flag_error,
5091 flag_stale, flag_parallel_rx, flag_queued,
5092 flag_zero_wait_count_rx, flag_immediate_delivery,
5093 flag_reo_required);
5094 snprintf(wait_count, sizeof(wait_count),
5095 "%9llx(%8x, %8x, %8x, %8x, %8x, %8x)",
5096 info->wait_count.total_count,
5097 info->wait_count.per_link_count[0],
5098 info->wait_count.per_link_count[1],
5099 info->wait_count.per_link_count[2],
5100 info->wait_count.per_link_count[3],
5101 info->wait_count.per_link_count[4],
5102 info->wait_count.per_link_count[5]);
5103
5104 for (link = 0; link < MAX_MLO_LINKS; link++) {
5105 char mac_hw[MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
5106 char fw_consumed[MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
5107 char fw_forwarded[MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
5108 char host[MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_SNAPSHOT_MAX_SIZE + 1] = {'\0'};
5109 struct mgmt_rx_reo_snapshot_params *mac_hw_ss;
5110 struct mgmt_rx_reo_snapshot_params *fw_consumed_ss;
5111 struct mgmt_rx_reo_snapshot_params *fw_forwarded_ss;
5112 struct mgmt_rx_reo_snapshot_params *host_ss;
5113
5114 mac_hw_ss = &info->shared_snapshots
5115 [link][MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW];
5116 fw_consumed_ss = &info->shared_snapshots
5117 [link][MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED];
5118 fw_forwarded_ss = &info->shared_snapshots
5119 [link][MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED];
5120 host_ss = &info->host_snapshot[link];
5121
5122 snprintf(mac_hw, sizeof(mac_hw), "(%1u, %5u, %10u)",
5123 mac_hw_ss->valid, mac_hw_ss->mgmt_pkt_ctr,
5124 mac_hw_ss->global_timestamp);
5125 snprintf(fw_consumed, sizeof(fw_consumed),
5126 "(%1u, %5u, %10u)",
5127 fw_consumed_ss->valid,
5128 fw_consumed_ss->mgmt_pkt_ctr,
5129 fw_consumed_ss->global_timestamp);
5130 snprintf(fw_forwarded, sizeof(fw_forwarded),
5131 "(%1u, %5u, %10u)",
5132 fw_forwarded_ss->valid,
5133 fw_forwarded_ss->mgmt_pkt_ctr,
5134 fw_forwarded_ss->global_timestamp);
5135 snprintf(host, sizeof(host), "(%1u, %5u, %10u)",
5136 host_ss->valid,
5137 host_ss->mgmt_pkt_ctr,
5138 host_ss->global_timestamp);
5139 snprintf(snapshots[link], sizeof(snapshots[link]),
5140 "%22s, %22s, %22s, %22s", mac_hw, fw_consumed,
5141 fw_forwarded, host);
5142 }
5143
5144 mgmt_rx_reo_alert_no_fl("|%5u|%5d|%6u|%6x|%9x|%4u|%5u|%10u|%10u|%10u|%5u|%10lld|%11llu|%11s|%4u|%11llu|%6d|%5d|%6d|%5d|%69s|%70s|%70s|%70s|%70s|%70s|%70s|",
5145 entry, info->cpu_id, info->desc_type,
5146 info->frame_type, info->frame_subtype,
5147 info->link_id,
5148 info->mgmt_pkt_ctr,
5149 info->global_timestamp,
5150 info->start_timestamp,
5151 info->end_timestamp,
5152 info->duration_us,
5153 ts_last_delivered_frame,
5154 info->ingress_timestamp, flags,
5155 info->queued_list,
5156 info->ingress_duration,
5157 info->ingress_list_size_rx,
5158 info->ingress_list_insertion_pos,
5159 info->egress_list_size_rx,
5160 info->egress_list_insertion_pos,
5161 wait_count,
5162 snapshots[0], snapshots[1],
5163 snapshots[2], snapshots[3],
5164 snapshots[4], snapshots[5]);
5165 mgmt_rx_reo_alert_no_fl("%s", boarder);
5166
5167 index++;
5168 index %= ingress_frame_debug_info->frame_list_size;
5169 }
5170
5171 return QDF_STATUS_SUCCESS;
5172 }
5173 #else
5174 /**
5175 * mgmt_rx_reo_debug_print_ingress_frame_stats() - API to print the stats
5176 * related to frames going into the reorder module
5177 * @reo_ctx: Pointer to reorder context
5178 *
5179 * API to print the stats related to frames going into the management
5180 * Rx reorder module.
5181 *
5182 * Return: QDF_STATUS
5183 */
5184 static QDF_STATUS
mgmt_rx_reo_debug_print_ingress_frame_stats(struct mgmt_rx_reo_context * reo_ctx)5185 mgmt_rx_reo_debug_print_ingress_frame_stats(struct mgmt_rx_reo_context *reo_ctx)
5186 {
5187 return QDF_STATUS_SUCCESS;
5188 }
5189
5190 /**
5191 * log_ingress_frame_entry() - Log the information about a frame at the start
5192 * of incoming frame processing
5193 * @reo_ctx: management rx reorder context
5194 * @desc: Pointer to frame descriptor
5195 *
5196 * Return: QDF_STATUS of operation
5197 */
5198 static QDF_STATUS
log_ingress_frame_entry(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_frame_descriptor * desc)5199 log_ingress_frame_entry(struct mgmt_rx_reo_context *reo_ctx,
5200 struct mgmt_rx_reo_frame_descriptor *desc)
5201 {
5202 return QDF_STATUS_SUCCESS;
5203 }
5204
5205 /**
5206 * log_ingress_frame_exit() - Log the information about a frame at the end of
5207 * incoming frame processing
5208 * @reo_ctx: management rx reorder context
5209 * @desc: Pointer to frame descriptor
5210 * @is_queued: Indicates whether this frame is queued to reorder list
5211 * @is_error: Indicates whether any error occurred during processing this frame
5212 * @context_id: context identifier
5213 * @link_id: Link ID
5214 *
5215 * Return: QDF_STATUS of operation
5216 */
5217 static QDF_STATUS
log_ingress_frame_exit(struct mgmt_rx_reo_context * reo_ctx,struct mgmt_rx_reo_frame_descriptor * desc,bool is_queued,bool is_error,int32_t context_id,uint8_t link_id)5218 log_ingress_frame_exit(struct mgmt_rx_reo_context *reo_ctx,
5219 struct mgmt_rx_reo_frame_descriptor *desc,
5220 bool is_queued, bool is_error,
5221 int32_t context_id, uint8_t link_id)
5222 {
5223 return QDF_STATUS_SUCCESS;
5224 }
5225
5226 /**
5227 * mgmt_rx_reo_debug_print_ingress_frame_info() - Print debug information about
5228 * the latest frames entering the reorder module
5229 * @reo_ctx: management rx reorder context
5230 *
5231 * Return: QDF_STATUS of operation
5232 */
5233 static QDF_STATUS
mgmt_rx_reo_debug_print_ingress_frame_info(struct mgmt_rx_reo_context * reo_ctx)5234 mgmt_rx_reo_debug_print_ingress_frame_info(struct mgmt_rx_reo_context *reo_ctx)
5235 {
5236 return QDF_STATUS_SUCCESS;
5237 }
5238 #endif /* WLAN_MGMT_RX_REO_DEBUG_SUPPORT */
5239
5240 QDF_STATUS
wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_frame_descriptor * desc,bool * is_queued)5241 wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
5242 struct mgmt_rx_reo_frame_descriptor *desc,
5243 bool *is_queued)
5244 {
5245 struct mgmt_rx_reo_context *reo_ctx;
5246 struct mgmt_rx_reo_ingress_list *ingress_list;
5247 struct mgmt_rx_reo_egress_list *egress_list;
5248 QDF_STATUS ret;
5249 int16_t cur_link;
5250 struct mgmt_rx_reo_context_info ctx_info = {0};
5251 int32_t context_id = 0;
5252
5253 if (!is_queued) {
5254 mgmt_rx_reo_err("Pointer to queued indication is null");
5255 return QDF_STATUS_E_NULL_VALUE;
5256 }
5257
5258 *is_queued = false;
5259
5260 if (!desc || !desc->rx_params) {
5261 mgmt_rx_reo_err("MGMT Rx REO descriptor or rx params are null");
5262 return QDF_STATUS_E_NULL_VALUE;
5263 }
5264
5265 reo_ctx = wlan_mgmt_rx_reo_get_ctx_from_pdev(pdev);
5266 if (!reo_ctx) {
5267 mgmt_rx_reo_err("REO context is NULL");
5268 return QDF_STATUS_E_NULL_VALUE;
5269 }
5270 ingress_list = &reo_ctx->ingress_list;
5271 egress_list = &reo_ctx->egress_list;
5272
5273 /**
5274 * Critical Section = Host snapshot update + Calculation of wait
5275 * counts + Update reorder list. Following section describes the
5276 * motivation for making this a critical section.
5277 * Lets take an example of 2 links (Link A & B) and each has received
5278 * a management frame A1 and B1 such that MLO global time stamp of A1 <
5279 * MLO global time stamp of B1. Host is concurrently executing
5280 * "wlan_mgmt_rx_reo_algo_entry" for A1 and B1 in 2 different CPUs.
5281 *
5282 * A lock less version of this API("wlan_mgmt_rx_reo_algo_entry_v1") is
5283 * as follows.
5284 *
5285 * wlan_mgmt_rx_reo_algo_entry()
5286 * {
5287 * Host snapshot update
5288 * Calculation of wait counts
5289 * Update reorder list
5290 * Release to upper layer
5291 * }
5292 *
5293 * We may run into race conditions under the following sequence of
5294 * operations.
5295 *
5296 * 1. Host snapshot update for link A in context of frame A1
5297 * 2. Host snapshot update for link B in context of frame B1
5298 * 3. Calculation of wait count for frame B1
5299 * link A wait count = 0
5300 * link B wait count = 0
5301 * 4. Update reorder list with frame B1
5302 * 5. Release B1 to upper layer
5303 * 6. Calculation of wait count for frame A1
5304 * link A wait count = 0
5305 * link B wait count = 0
5306 * 7. Update reorder list with frame A1
5307 * 8. Release A1 to upper layer
5308 *
5309 * This leads to incorrect behaviour as B1 goes to upper layer before
5310 * A1.
5311 *
5312 * To prevent this lets make Host snapshot update + Calculate wait count
5313 * a critical section by adding locks. The updated version of the API
5314 * ("wlan_mgmt_rx_reo_algo_entry_v2") is as follows.
5315 *
5316 * wlan_mgmt_rx_reo_algo_entry()
5317 * {
5318 * LOCK
5319 * Host snapshot update
5320 * Calculation of wait counts
5321 * UNLOCK
5322 * Update reorder list
5323 * Release to upper layer
5324 * }
5325 *
5326 * With this API also We may run into race conditions under the
5327 * following sequence of operations.
5328 *
5329 * 1. Host snapshot update for link A in context of frame A1 +
5330 * Calculation of wait count for frame A1
5331 * link A wait count = 0
5332 * link B wait count = 0
5333 * 2. Host snapshot update for link B in context of frame B1 +
5334 * Calculation of wait count for frame B1
5335 * link A wait count = 0
5336 * link B wait count = 0
5337 * 4. Update reorder list with frame B1
5338 * 5. Release B1 to upper layer
5339 * 7. Update reorder list with frame A1
5340 * 8. Release A1 to upper layer
5341 *
5342 * This also leads to incorrect behaviour as B1 goes to upper layer
5343 * before A1.
5344 *
5345 * To prevent this, let's make Host snapshot update + Calculate wait
5346 * count + Update reorder list a critical section by adding locks.
5347 * The updated version of the API ("wlan_mgmt_rx_reo_algo_entry_final")
5348 * is as follows.
5349 *
5350 * wlan_mgmt_rx_reo_algo_entry()
5351 * {
5352 * LOCK
5353 * Host snapshot update
5354 * Calculation of wait counts
5355 * Update reorder list
5356 * UNLOCK
5357 * Release to upper layer
5358 * }
5359 */
5360 qdf_spin_lock(&reo_ctx->reo_algo_entry_lock);
5361
5362 cur_link = mgmt_rx_reo_get_link_id(desc->rx_params);
5363 if (desc->frame_type != IEEE80211_FC0_TYPE_MGT) {
5364 ret = QDF_STATUS_E_INVAL;
5365 goto failure;
5366 }
5367
5368 ret = log_ingress_frame_entry(reo_ctx, desc);
5369 if (QDF_IS_STATUS_ERROR(ret))
5370 goto failure;
5371
5372 ret = check_frame_sanity(pdev, desc);
5373 if (QDF_IS_STATUS_ERROR(ret))
5374 goto failure;
5375
5376 /* Update the Host snapshot */
5377 ret = wlan_mgmt_rx_reo_update_host_snapshot(pdev, desc);
5378 if (QDF_IS_STATUS_ERROR(ret))
5379 goto failure;
5380
5381 if (desc->drop)
5382 goto failure;
5383
5384 /* Compute wait count for this frame/event */
5385 ret = wlan_mgmt_rx_reo_algo_calculate_wait_count(pdev, desc);
5386 if (QDF_IS_STATUS_ERROR(ret))
5387 goto failure;
5388
5389 ctx_info.in_reo_params = *desc->rx_params->reo_params;
5390 /* Update ingress and egress list */
5391 ret = mgmt_rx_reo_update_lists(ingress_list, egress_list, desc,
5392 is_queued);
5393 if (QDF_IS_STATUS_ERROR(ret))
5394 goto failure;
5395
5396 context_id = qdf_atomic_inc_return(&reo_ctx->context_id);
5397 ret = log_ingress_frame_exit(reo_ctx, desc, *is_queued,
5398 false, context_id, cur_link);
5399 if (QDF_IS_STATUS_ERROR(ret)) {
5400 qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
5401 return ret;
5402 }
5403
5404 qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
5405
5406 ret = mgmt_rx_reo_move_entries_ingress_to_egress_list(ingress_list,
5407 egress_list);
5408 if (QDF_IS_STATUS_ERROR(ret))
5409 return ret;
5410
5411 ctx_info.context = MGMT_RX_REO_CONTEXT_MGMT_RX;
5412 ctx_info.context_id = context_id;
5413
5414 /* Finally, release the entries for which pending frame is received */
5415 return mgmt_rx_reo_release_egress_list_entries(reo_ctx, 1 << cur_link,
5416 &ctx_info);
5417
5418 failure:
5419 /**
5420 * Ignore the return value of this function call, return
5421 * the actual reason for failure.
5422 */
5423 log_ingress_frame_exit(reo_ctx, desc, *is_queued, true,
5424 context_id, cur_link);
5425
5426 qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
5427
5428 return ret;
5429 }
5430
5431 #ifndef WLAN_MGMT_RX_REO_SIM_SUPPORT
5432 /**
5433 * mgmt_rx_reo_sim_init() - Initialize management rx reorder simulation
5434 * context.
5435 * @reo_context: Pointer to reo context
5436 *
5437 * Return: QDF_STATUS of operation
5438 */
5439 static inline QDF_STATUS
mgmt_rx_reo_sim_init(struct mgmt_rx_reo_context * reo_context)5440 mgmt_rx_reo_sim_init(struct mgmt_rx_reo_context *reo_context)
5441 {
5442 return QDF_STATUS_SUCCESS;
5443 }
5444
5445 /**
5446 * mgmt_rx_reo_sim_deinit() - De initialize management rx reorder simulation
5447 * context.
5448 * @reo_context: Pointer to reo context
5449 *
5450 * Return: QDF_STATUS of operation
5451 */
5452 static inline QDF_STATUS
mgmt_rx_reo_sim_deinit(struct mgmt_rx_reo_context * reo_context)5453 mgmt_rx_reo_sim_deinit(struct mgmt_rx_reo_context *reo_context)
5454 {
5455 return QDF_STATUS_SUCCESS;
5456 }
5457
5458 QDF_STATUS
mgmt_rx_reo_sim_pdev_object_create_notification(struct wlan_objmgr_pdev * pdev)5459 mgmt_rx_reo_sim_pdev_object_create_notification(struct wlan_objmgr_pdev *pdev)
5460 {
5461 return QDF_STATUS_SUCCESS;
5462 }
5463
5464 QDF_STATUS
mgmt_rx_reo_sim_pdev_object_destroy_notification(struct wlan_objmgr_pdev * pdev)5465 mgmt_rx_reo_sim_pdev_object_destroy_notification(struct wlan_objmgr_pdev *pdev)
5466 {
5467 return QDF_STATUS_SUCCESS;
5468 }
5469 #else
5470 /**
5471 * mgmt_rx_reo_sim_remove_frame_from_master_list() - Removes frame from the
5472 * master management frame list
5473 * @master_frame_list: pointer to master management frame list
5474 * @frame: pointer to management frame parameters
5475 *
5476 * This API removes frames from the master management frame list. This API is
5477 * used in case of FW consumed management frames or management frames which
5478 * are dropped at host due to any error.
5479 *
5480 * Return: QDF_STATUS of operation
5481 */
5482 static QDF_STATUS
mgmt_rx_reo_sim_remove_frame_from_master_list(struct mgmt_rx_reo_master_frame_list * master_frame_list,const struct mgmt_rx_frame_params * frame)5483 mgmt_rx_reo_sim_remove_frame_from_master_list(
5484 struct mgmt_rx_reo_master_frame_list *master_frame_list,
5485 const struct mgmt_rx_frame_params *frame)
5486 {
5487 struct mgmt_rx_reo_pending_frame_list_entry *pending_entry;
5488 struct mgmt_rx_reo_pending_frame_list_entry *matching_pend_entry = NULL;
5489 struct mgmt_rx_reo_stale_frame_list_entry *stale_entry;
5490 struct mgmt_rx_reo_stale_frame_list_entry *matching_stale_entry = NULL;
5491 QDF_STATUS status;
5492
5493 if (!master_frame_list) {
5494 mgmt_rx_reo_err("Mgmt master frame list is null");
5495 return QDF_STATUS_E_NULL_VALUE;
5496 }
5497
5498 if (!frame) {
5499 mgmt_rx_reo_err("Pointer to mgmt frame params is null");
5500 return QDF_STATUS_E_NULL_VALUE;
5501 }
5502
5503 qdf_spin_lock(&master_frame_list->lock);
5504
5505 qdf_list_for_each(&master_frame_list->pending_list, pending_entry,
5506 node) {
5507 if (pending_entry->params.link_id == frame->link_id &&
5508 pending_entry->params.mgmt_pkt_ctr == frame->mgmt_pkt_ctr &&
5509 pending_entry->params.global_timestamp ==
5510 frame->global_timestamp) {
5511 matching_pend_entry = pending_entry;
5512 break;
5513 }
5514 }
5515
5516 qdf_list_for_each(&master_frame_list->stale_list, stale_entry, node) {
5517 if (stale_entry->params.link_id == frame->link_id &&
5518 stale_entry->params.mgmt_pkt_ctr == frame->mgmt_pkt_ctr &&
5519 stale_entry->params.global_timestamp ==
5520 frame->global_timestamp) {
5521 matching_stale_entry = stale_entry;
5522 break;
5523 }
5524 }
5525
5526 /* Found in pending and stale list. Duplicate entries, assert */
5527 qdf_assert_always(!matching_pend_entry || !matching_stale_entry);
5528
5529 if (!matching_pend_entry && !matching_stale_entry) {
5530 qdf_spin_unlock(&master_frame_list->lock);
5531 mgmt_rx_reo_err("No matching frame in pend/stale list");
5532 return QDF_STATUS_E_FAILURE;
5533 }
5534
5535 if (matching_pend_entry) {
5536 status = qdf_list_remove_node(&master_frame_list->pending_list,
5537 &matching_pend_entry->node);
5538 if (QDF_IS_STATUS_ERROR(status)) {
5539 qdf_spin_unlock(&master_frame_list->lock);
5540 mgmt_rx_reo_err("Failed to remove the matching entry");
5541 return status;
5542 }
5543
5544 qdf_mem_free(matching_pend_entry);
5545 }
5546
5547 if (matching_stale_entry) {
5548 status = qdf_list_remove_node(&master_frame_list->stale_list,
5549 &matching_stale_entry->node);
5550 if (QDF_IS_STATUS_ERROR(status)) {
5551 qdf_spin_unlock(&master_frame_list->lock);
5552 mgmt_rx_reo_err("Failed to remove the matching entry");
5553 return status;
5554 }
5555
5556 qdf_mem_free(matching_stale_entry);
5557 }
5558
5559 qdf_spin_unlock(&master_frame_list->lock);
5560
5561 return QDF_STATUS_SUCCESS;
5562 }
5563
5564 /**
5565 * mgmt_rx_reo_sim_remove_frame_from_pending_list() - Removes frame from the
5566 * pending management frame list
5567 * @master_frame_list: pointer to master management frame list
5568 * @frame: pointer to management frame parameters
5569 *
5570 * This API removes frames from the pending management frame list. This API is
5571 * used in case of FW consumed management frames or management frames which
5572 * are dropped at host due to any error.
5573 *
5574 * Return: QDF_STATUS of operation
5575 */
5576 static QDF_STATUS
mgmt_rx_reo_sim_remove_frame_from_pending_list(struct mgmt_rx_reo_master_frame_list * master_frame_list,const struct mgmt_rx_frame_params * frame)5577 mgmt_rx_reo_sim_remove_frame_from_pending_list(
5578 struct mgmt_rx_reo_master_frame_list *master_frame_list,
5579 const struct mgmt_rx_frame_params *frame)
5580 {
5581 struct mgmt_rx_reo_pending_frame_list_entry *cur_entry;
5582 struct mgmt_rx_reo_pending_frame_list_entry *matching_entry = NULL;
5583 QDF_STATUS status;
5584
5585 if (!master_frame_list) {
5586 mgmt_rx_reo_err("Mgmt master frame list is null");
5587 return QDF_STATUS_E_NULL_VALUE;
5588 }
5589
5590 if (!frame) {
5591 mgmt_rx_reo_err("Pointer to mgmt frame params is null");
5592 return QDF_STATUS_E_NULL_VALUE;
5593 }
5594
5595 qdf_spin_lock(&master_frame_list->lock);
5596
5597 qdf_list_for_each(&master_frame_list->pending_list, cur_entry, node) {
5598 if (cur_entry->params.link_id == frame->link_id &&
5599 cur_entry->params.mgmt_pkt_ctr == frame->mgmt_pkt_ctr &&
5600 cur_entry->params.global_timestamp ==
5601 frame->global_timestamp) {
5602 matching_entry = cur_entry;
5603 break;
5604 }
5605 }
5606
5607 if (!matching_entry) {
5608 qdf_spin_unlock(&master_frame_list->lock);
5609 mgmt_rx_reo_err("No matching frame in the pend list to remove");
5610 return QDF_STATUS_E_FAILURE;
5611 }
5612
5613 status = qdf_list_remove_node(&master_frame_list->pending_list,
5614 &matching_entry->node);
5615 if (QDF_IS_STATUS_ERROR(status)) {
5616 qdf_spin_unlock(&master_frame_list->lock);
5617 mgmt_rx_reo_err("Failed to remove the matching entry");
5618 return status;
5619 }
5620
5621 qdf_mem_free(matching_entry);
5622
5623 qdf_spin_unlock(&master_frame_list->lock);
5624
5625
5626 return QDF_STATUS_SUCCESS;
5627 }
5628
5629 /**
5630 * mgmt_rx_reo_sim_add_frame_to_pending_list() - Inserts frame to the
5631 * pending management frame list
5632 * @master_frame_list: pointer to master management frame list
5633 * @frame: pointer to management frame parameters
5634 *
5635 * This API inserts frames to the pending management frame list. This API is
5636 * used to insert frames generated by the MAC HW to the pending frame list.
5637 *
5638 * Return: QDF_STATUS of operation
5639 */
5640 static QDF_STATUS
mgmt_rx_reo_sim_add_frame_to_pending_list(struct mgmt_rx_reo_master_frame_list * master_frame_list,const struct mgmt_rx_frame_params * frame)5641 mgmt_rx_reo_sim_add_frame_to_pending_list(
5642 struct mgmt_rx_reo_master_frame_list *master_frame_list,
5643 const struct mgmt_rx_frame_params *frame)
5644 {
5645 struct mgmt_rx_reo_pending_frame_list_entry *new_entry;
5646 QDF_STATUS status;
5647
5648 if (!master_frame_list) {
5649 mgmt_rx_reo_err("Mgmt master frame list is null");
5650 return QDF_STATUS_E_NULL_VALUE;
5651 }
5652
5653 if (!frame) {
5654 mgmt_rx_reo_err("Pointer mgmt frame params is null");
5655 return QDF_STATUS_E_NULL_VALUE;
5656 }
5657
5658 new_entry = qdf_mem_malloc(sizeof(*new_entry));
5659 if (!new_entry) {
5660 mgmt_rx_reo_err("Failed to allocate new entry to frame list");
5661 return QDF_STATUS_E_NOMEM;
5662 }
5663
5664 new_entry->params = *frame;
5665
5666 qdf_spin_lock(&master_frame_list->lock);
5667
5668 status = qdf_list_insert_back(&master_frame_list->pending_list,
5669 &new_entry->node);
5670
5671 qdf_spin_unlock(&master_frame_list->lock);
5672
5673 if (QDF_IS_STATUS_ERROR(status)) {
5674 mgmt_rx_reo_err("Failed to add frame to pending list");
5675 qdf_mem_free(new_entry);
5676 return status;
5677 }
5678
5679 return QDF_STATUS_SUCCESS;
5680 }
5681
5682 QDF_STATUS
mgmt_rx_reo_sim_process_rx_frame(struct wlan_objmgr_pdev * pdev,qdf_nbuf_t buf,struct mgmt_rx_event_params * mgmt_rx_params)5683 mgmt_rx_reo_sim_process_rx_frame(struct wlan_objmgr_pdev *pdev, qdf_nbuf_t buf,
5684 struct mgmt_rx_event_params *mgmt_rx_params)
5685 {
5686 struct mgmt_rx_reo_context *reo_context;
5687 struct mgmt_rx_reo_sim_context *sim_context;
5688 QDF_STATUS status;
5689 struct mgmt_rx_reo_params *reo_params;
5690
5691 if (!mgmt_rx_params) {
5692 mgmt_rx_reo_err("Mgmt rx params null");
5693 return QDF_STATUS_E_NULL_VALUE;
5694 }
5695
5696 reo_params = mgmt_rx_params->reo_params;
5697
5698 reo_context = wlan_mgmt_rx_reo_get_ctx_from_pdev(pdev);
5699 if (!reo_context) {
5700 mgmt_rx_reo_err("Mgmt reo context is null");
5701 return QDF_STATUS_E_NULL_VALUE;
5702 }
5703
5704 sim_context = &reo_context->sim_context;
5705
5706 qdf_spin_lock(&sim_context->master_frame_list.lock);
5707
5708 if (qdf_list_empty(&sim_context->master_frame_list.pending_list)) {
5709 qdf_spin_unlock(&sim_context->master_frame_list.lock);
5710 mgmt_rx_reo_err("reo sim failure: pending frame list is empty");
5711 qdf_assert_always(0);
5712 } else {
5713 struct mgmt_rx_frame_params *cur_entry_params;
5714 struct mgmt_rx_reo_pending_frame_list_entry *cur_entry;
5715 struct mgmt_rx_reo_pending_frame_list_entry *matching_entry = NULL;
5716
5717 /**
5718 * Make sure the frames delivered to upper layer are in the
5719 * increasing order of global time stamp. For that the frame
5720 * which is being delivered should be present at the head of the
5721 * pending frame list. There could be multiple frames with the
5722 * same global time stamp in the pending frame list. Search
5723 * among all the frames at the head of the list which has the
5724 * same global time stamp as the frame which is being delivered.
5725 * To find matching frame, check whether packet counter,
5726 * global time stamp and link id are same.
5727 */
5728 qdf_list_for_each(&sim_context->master_frame_list.pending_list,
5729 cur_entry, node) {
5730 cur_entry_params = &cur_entry->params;
5731
5732 if (cur_entry_params->global_timestamp !=
5733 reo_params->global_timestamp)
5734 break;
5735
5736 if (cur_entry_params->link_id == reo_params->link_id &&
5737 cur_entry_params->mgmt_pkt_ctr ==
5738 reo_params->mgmt_pkt_ctr) {
5739 matching_entry = cur_entry;
5740 break;
5741 }
5742 }
5743
5744 if (!matching_entry) {
5745 qdf_spin_unlock(&sim_context->master_frame_list.lock);
5746 mgmt_rx_reo_err("reo sim failure: mismatch");
5747 qdf_assert_always(0);
5748 }
5749
5750 status = qdf_list_remove_node(
5751 &sim_context->master_frame_list.pending_list,
5752 &matching_entry->node);
5753 qdf_mem_free(matching_entry);
5754
5755 if (QDF_IS_STATUS_ERROR(status)) {
5756 qdf_spin_unlock(&sim_context->master_frame_list.lock);
5757 mgmt_rx_reo_err("Failed to remove matching entry");
5758 return status;
5759 }
5760 }
5761
5762 qdf_spin_unlock(&sim_context->master_frame_list.lock);
5763
5764 mgmt_rx_reo_debug("Successfully processed mgmt frame");
5765 mgmt_rx_reo_debug("link_id = %u, ctr = %u, ts = %u",
5766 reo_params->link_id, reo_params->mgmt_pkt_ctr,
5767 reo_params->global_timestamp);
5768
5769 return QDF_STATUS_SUCCESS;
5770 }
5771
5772 /**
5773 * mgmt_rx_reo_sim_get_random_bool() - Generate true/false randomly
5774 * @percentage_true: probability (in percentage) of true
5775 *
5776 * API to generate true with probability @percentage_true % and false with
5777 * probability (100 - @percentage_true) %.
5778 *
5779 * Return: true with probability @percentage_true % and false with probability
5780 * (100 - @percentage_true) %
5781 */
5782 static bool
mgmt_rx_reo_sim_get_random_bool(uint8_t percentage_true)5783 mgmt_rx_reo_sim_get_random_bool(uint8_t percentage_true)
5784 {
5785 uint32_t rand;
5786
5787 if (percentage_true > 100) {
5788 mgmt_rx_reo_err("Invalid probability value for true, %u",
5789 percentage_true);
5790 return -EINVAL;
5791 }
5792
5793 get_random_bytes(&rand, sizeof(rand));
5794
5795 return ((rand % 100) < percentage_true);
5796 }
5797
5798 /**
5799 * mgmt_rx_reo_sim_get_random_unsigned_int() - Generate random unsigned integer
5800 * value in the range [0, max)
5801 * @max: upper limit for the output
5802 *
5803 * API to generate random unsigned integer value in the range [0, max).
5804 *
5805 * Return: unsigned integer value in the range [0, max)
5806 */
5807 static uint32_t
mgmt_rx_reo_sim_get_random_unsigned_int(uint32_t max)5808 mgmt_rx_reo_sim_get_random_unsigned_int(uint32_t max)
5809 {
5810 uint32_t rand;
5811
5812 get_random_bytes(&rand, sizeof(rand));
5813
5814 return (rand % max);
5815 }
5816
5817 /**
5818 * mgmt_rx_reo_sim_sleep() - Wrapper API to sleep for given micro seconds
5819 * @sleeptime_us: Sleep time in micro seconds
5820 *
5821 * This API uses msleep() internally. So the granularity is limited to
5822 * milliseconds.
5823 *
5824 * Return: none
5825 */
5826 static void
mgmt_rx_reo_sim_sleep(uint32_t sleeptime_us)5827 mgmt_rx_reo_sim_sleep(uint32_t sleeptime_us)
5828 {
5829 msleep(sleeptime_us / USEC_PER_MSEC);
5830 }
5831
5832 /**
5833 * mgmt_rx_reo_sim_frame_handler_host() - Management frame handler at the host
5834 * layer
5835 * @arg: Argument
5836 *
5837 * This API handles the management frame at the host layer. This is applicable
5838 * for simulation alone.
5839 *
5840 * Return: none
5841 */
5842 static void
mgmt_rx_reo_sim_frame_handler_host(void * arg)5843 mgmt_rx_reo_sim_frame_handler_host(void *arg)
5844 {
5845 struct mgmt_rx_frame_fw *frame_fw = (struct mgmt_rx_frame_fw *)arg;
5846 uint32_t fw_to_host_delay_us;
5847 bool is_error_frame = false;
5848 int8_t link_id = -1;
5849 struct mgmt_rx_event_params *rx_params;
5850 QDF_STATUS status;
5851 struct mgmt_rx_reo_sim_context *sim_context;
5852 struct wlan_objmgr_pdev *pdev;
5853 uint8_t ml_grp_id;
5854
5855 if (!frame_fw) {
5856 mgmt_rx_reo_err("HOST-%d : Pointer to FW frame struct is null",
5857 link_id);
5858 goto error_print;
5859 }
5860
5861 link_id = frame_fw->params.link_id;
5862
5863 sim_context = frame_fw->sim_context;
5864 if (!sim_context) {
5865 mgmt_rx_reo_err("HOST-%d : Mgmt rx reo simulation context null",
5866 link_id);
5867 goto error_free_fw_frame;
5868 }
5869
5870 ml_grp_id = sim_context->mlo_grp_id;
5871
5872 fw_to_host_delay_us = MGMT_RX_REO_SIM_DELAY_FW_TO_HOST_MIN +
5873 mgmt_rx_reo_sim_get_random_unsigned_int(
5874 MGMT_RX_REO_SIM_DELAY_FW_TO_HOST_MIN_MAX_DELTA);
5875
5876 mgmt_rx_reo_sim_sleep(fw_to_host_delay_us);
5877
5878 if (!frame_fw->is_consumed_by_fw) {
5879 is_error_frame = mgmt_rx_reo_sim_get_random_bool(
5880 MGMT_RX_REO_SIM_PERCENTAGE_ERROR_FRAMES);
5881
5882 /**
5883 * This frame should be present in pending/stale list of the
5884 * master frame list. Error frames need not be reordered
5885 * by reorder algorithm. It is just used for book
5886 * keeping purposes. Hence remove it from the master list.
5887 */
5888 if (is_error_frame) {
5889 status = mgmt_rx_reo_sim_remove_frame_from_master_list(
5890 &sim_context->master_frame_list,
5891 &frame_fw->params);
5892
5893 if (QDF_IS_STATUS_ERROR(status)) {
5894 mgmt_rx_reo_err("HOST-%d : Failed to remove error frame",
5895 link_id);
5896 qdf_assert_always(0);
5897 }
5898 }
5899 }
5900
5901 mgmt_rx_reo_debug("HOST-%d : Received frame with ts = %u, ctr = %u, consume = %u, error = %u",
5902 link_id, frame_fw->params.global_timestamp,
5903 frame_fw->params.mgmt_pkt_ctr,
5904 frame_fw->is_consumed_by_fw, is_error_frame);
5905
5906 rx_params = alloc_mgmt_rx_event_params();
5907 if (!rx_params) {
5908 mgmt_rx_reo_err("HOST-%d : Failed to allocate event params",
5909 link_id);
5910 goto error_free_fw_frame;
5911 }
5912
5913 rx_params->reo_params->link_id = frame_fw->params.link_id;
5914 rx_params->reo_params->global_timestamp =
5915 frame_fw->params.global_timestamp;
5916 rx_params->reo_params->mgmt_pkt_ctr = frame_fw->params.mgmt_pkt_ctr;
5917 rx_params->reo_params->valid = true;
5918
5919 pdev = wlan_get_pdev_from_mlo_link_id(
5920 link_id, ml_grp_id, WLAN_MGMT_RX_REO_SIM_ID);
5921 if (!pdev) {
5922 mgmt_rx_reo_err("No pdev corresponding to link_id %d", link_id);
5923 goto error_free_mgmt_rx_event_params;
5924 }
5925
5926 if (is_error_frame) {
5927 status = tgt_mgmt_rx_reo_host_drop_handler(
5928 pdev, rx_params->reo_params);
5929 free_mgmt_rx_event_params(rx_params);
5930 } else if (frame_fw->is_consumed_by_fw) {
5931 status = tgt_mgmt_rx_reo_fw_consumed_event_handler(
5932 pdev, rx_params->reo_params);
5933 free_mgmt_rx_event_params(rx_params);
5934 } else {
5935 status = tgt_mgmt_rx_reo_frame_handler(pdev, NULL, rx_params);
5936 }
5937
5938 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_SIM_ID);
5939
5940 if (QDF_IS_STATUS_ERROR(status)) {
5941 mgmt_rx_reo_err("Failed to execute reo algorithm");
5942 goto error_free_fw_frame;
5943 }
5944
5945 qdf_mem_free(frame_fw);
5946
5947 return;
5948
5949 error_free_mgmt_rx_event_params:
5950 free_mgmt_rx_event_params(rx_params);
5951 error_free_fw_frame:
5952 qdf_mem_free(frame_fw);
5953 error_print:
5954 mgmt_rx_reo_err("HOST-%d : Exiting host frame handler due to error",
5955 link_id);
5956 }
5957
5958 /**
5959 * mgmt_rx_reo_sim_write_snapshot() - API to write snapshots used for management
5960 * frame reordering
5961 * @link_id: link id
5962 * @id: snapshot id
5963 * @value: snapshot value
5964 * @ml_grp_id: MLO group id which it belongs to
5965 *
5966 * This API writes the snapshots used for management frame reordering. MAC HW
5967 * and FW can use this API to update the MAC HW/FW consumed/FW forwarded
5968 * snapshots.
5969 *
5970 * Return: QDF_STATUS
5971 */
5972 static QDF_STATUS
mgmt_rx_reo_sim_write_snapshot(uint8_t link_id,uint8_t ml_grp_id,enum mgmt_rx_reo_shared_snapshot_id id,struct mgmt_rx_reo_shared_snapshot value)5973 mgmt_rx_reo_sim_write_snapshot(uint8_t link_id, uint8_t ml_grp_id,
5974 enum mgmt_rx_reo_shared_snapshot_id id,
5975 struct mgmt_rx_reo_shared_snapshot value)
5976 {
5977 struct wlan_objmgr_pdev *pdev;
5978 struct mgmt_rx_reo_shared_snapshot *snapshot_address;
5979 QDF_STATUS status;
5980
5981 pdev = wlan_get_pdev_from_mlo_link_id(
5982 link_id, ml_grp_id,
5983 WLAN_MGMT_RX_REO_SIM_ID);
5984
5985 if (!pdev) {
5986 mgmt_rx_reo_err("pdev is null");
5987 return QDF_STATUS_E_NULL_VALUE;
5988 }
5989
5990 status = mgmt_rx_reo_sim_get_snapshot_address(pdev, id,
5991 &snapshot_address);
5992
5993 wlan_objmgr_pdev_release_ref(pdev, WLAN_MGMT_RX_REO_SIM_ID);
5994
5995 if (QDF_IS_STATUS_ERROR(status)) {
5996 mgmt_rx_reo_err("Failed to get snapshot address %d of pdev %pK",
5997 id, pdev);
5998 return QDF_STATUS_E_FAILURE;
5999 }
6000
6001 snapshot_address->mgmt_rx_reo_snapshot_low =
6002 value.mgmt_rx_reo_snapshot_low;
6003 snapshot_address->mgmt_rx_reo_snapshot_high =
6004 value.mgmt_rx_reo_snapshot_high;
6005
6006 return QDF_STATUS_SUCCESS;
6007 }
6008
6009 #define MGMT_RX_REO_SNAPSHOT_LOW_VALID_POS (0)
6010 #define MGMT_RX_REO_SNAPSHOT_LOW_VALID_SIZE (1)
6011 #define MGMT_RX_REO_SNAPSHOT_LOW_MGMT_PKT_CTR_POS (1)
6012 #define MGMT_RX_REO_SNAPSHOT_LOW_MGMT_PKT_CTR_SIZE (16)
6013 #define MGMT_RX_REO_SNAPSHOT_LOW_GLOBAL_TIMESTAMP_POS (17)
6014 #define MGMT_RX_REO_SNAPSHOT_LOW_GLOBAL_TIMESTAMP_SIZE (15)
6015
6016 #define MGMT_RX_REO_SNAPSHOT_HIGH_GLOBAL_TIMESTAMP_POS (0)
6017 #define MGMT_RX_REO_SNAPSHOT_HIGH_GLOBAL_TIMESTAMP_SIZE (17)
6018 #define MGMT_RX_REO_SNAPSHOT_HIGH_MGMT_PKT_CTR_REDUNDANT_POS (17)
6019 #define MGMT_RX_REO_SNAPSHOT_HIGH_MGMT_PKT_CTR_REDUNDANT_SIZE (15)
6020
6021 /**
6022 * mgmt_rx_reo_sim_get_snapshot_value() - API to get snapshot value for a given
6023 * management frame
6024 * @global_timestamp: global time stamp
6025 * @mgmt_pkt_ctr: management packet counter
6026 *
6027 * This API gets the snapshot value for a frame with time stamp
6028 * @global_timestamp and sequence number @mgmt_pkt_ctr.
6029 *
6030 * Return: snapshot value (struct mgmt_rx_reo_shared_snapshot)
6031 */
6032 static struct mgmt_rx_reo_shared_snapshot
mgmt_rx_reo_sim_get_snapshot_value(uint32_t global_timestamp,uint16_t mgmt_pkt_ctr)6033 mgmt_rx_reo_sim_get_snapshot_value(uint32_t global_timestamp,
6034 uint16_t mgmt_pkt_ctr)
6035 {
6036 struct mgmt_rx_reo_shared_snapshot snapshot = {0};
6037
6038 QDF_SET_BITS(snapshot.mgmt_rx_reo_snapshot_low,
6039 MGMT_RX_REO_SNAPSHOT_LOW_VALID_POS,
6040 MGMT_RX_REO_SNAPSHOT_LOW_VALID_SIZE, 1);
6041 QDF_SET_BITS(snapshot.mgmt_rx_reo_snapshot_low,
6042 MGMT_RX_REO_SNAPSHOT_LOW_MGMT_PKT_CTR_POS,
6043 MGMT_RX_REO_SNAPSHOT_LOW_MGMT_PKT_CTR_SIZE, mgmt_pkt_ctr);
6044 QDF_SET_BITS(snapshot.mgmt_rx_reo_snapshot_low,
6045 MGMT_RX_REO_SNAPSHOT_LOW_GLOBAL_TIMESTAMP_POS,
6046 MGMT_RX_REO_SNAPSHOT_LOW_GLOBAL_TIMESTAMP_SIZE,
6047 global_timestamp);
6048
6049 QDF_SET_BITS(snapshot.mgmt_rx_reo_snapshot_high,
6050 MGMT_RX_REO_SNAPSHOT_HIGH_GLOBAL_TIMESTAMP_POS,
6051 MGMT_RX_REO_SNAPSHOT_HIGH_GLOBAL_TIMESTAMP_SIZE,
6052 global_timestamp >> 15);
6053 QDF_SET_BITS(snapshot.mgmt_rx_reo_snapshot_high,
6054 MGMT_RX_REO_SNAPSHOT_HIGH_MGMT_PKT_CTR_REDUNDANT_POS,
6055 MGMT_RX_REO_SNAPSHOT_HIGH_MGMT_PKT_CTR_REDUNDANT_SIZE,
6056 mgmt_pkt_ctr);
6057
6058 return snapshot;
6059 }
6060
6061 /**
6062 * mgmt_rx_reo_sim_frame_handler_fw() - Management frame handler at the fw layer
6063 * @arg: Argument
6064 *
6065 * This API handles the management frame at the fw layer. This is applicable
6066 * for simulation alone.
6067 *
6068 * Return: none
6069 */
6070 static void
mgmt_rx_reo_sim_frame_handler_fw(void * arg)6071 mgmt_rx_reo_sim_frame_handler_fw(void *arg)
6072 {
6073 struct mgmt_rx_frame_mac_hw *frame_hw =
6074 (struct mgmt_rx_frame_mac_hw *)arg;
6075 uint32_t mac_hw_to_fw_delay_us;
6076 bool is_consumed_by_fw;
6077 struct mgmt_rx_frame_fw *frame_fw;
6078 int8_t link_id = -1;
6079 QDF_STATUS status;
6080 struct mgmt_rx_reo_sim_context *sim_context;
6081 enum mgmt_rx_reo_shared_snapshot_id snapshot_id;
6082 struct mgmt_rx_reo_shared_snapshot snapshot_value;
6083 bool ret;
6084 uint8_t ml_grp_id;
6085
6086 if (!frame_hw) {
6087 mgmt_rx_reo_err("FW-%d : Pointer to HW frame struct is null",
6088 link_id);
6089 qdf_assert_always(0);
6090 }
6091
6092 link_id = frame_hw->params.link_id;
6093
6094 sim_context = frame_hw->sim_context;
6095 if (!sim_context) {
6096 mgmt_rx_reo_err("FW-%d : Mgmt rx reo simulation context null",
6097 link_id);
6098 goto error_free_mac_hw_frame;
6099 }
6100
6101 ml_grp_id = sim_context->mlo_grp_id;
6102
6103 mac_hw_to_fw_delay_us = MGMT_RX_REO_SIM_DELAY_MAC_HW_TO_FW_MIN +
6104 mgmt_rx_reo_sim_get_random_unsigned_int(
6105 MGMT_RX_REO_SIM_DELAY_MAC_HW_TO_FW_MIN_MAX_DELTA);
6106 mgmt_rx_reo_sim_sleep(mac_hw_to_fw_delay_us);
6107
6108 is_consumed_by_fw = mgmt_rx_reo_sim_get_random_bool(
6109 MGMT_RX_REO_SIM_PERCENTAGE_FW_CONSUMED_FRAMES);
6110
6111 if (is_consumed_by_fw) {
6112 /**
6113 * This frame should be present in pending/stale list of the
6114 * master frame list. FW consumed frames need not be reordered
6115 * by reorder algorithm. It is just used for book
6116 * keeping purposes. Hence remove it from the master list.
6117 */
6118 status = mgmt_rx_reo_sim_remove_frame_from_master_list(
6119 &sim_context->master_frame_list,
6120 &frame_hw->params);
6121
6122 if (QDF_IS_STATUS_ERROR(status)) {
6123 mgmt_rx_reo_err("FW-%d : Failed to remove FW consumed frame",
6124 link_id);
6125 qdf_assert_always(0);
6126 }
6127 }
6128
6129 mgmt_rx_reo_debug("FW-%d : Processing frame with ts = %u, ctr = %u, consume = %u",
6130 link_id, frame_hw->params.global_timestamp,
6131 frame_hw->params.mgmt_pkt_ctr, is_consumed_by_fw);
6132
6133 frame_fw = qdf_mem_malloc(sizeof(*frame_fw));
6134 if (!frame_fw) {
6135 mgmt_rx_reo_err("FW-%d : Failed to allocate FW mgmt frame",
6136 link_id);
6137 goto error_free_mac_hw_frame;
6138 }
6139
6140 frame_fw->params = frame_hw->params;
6141 frame_fw->is_consumed_by_fw = is_consumed_by_fw;
6142 frame_fw->sim_context = frame_hw->sim_context;
6143
6144 snapshot_id = is_consumed_by_fw ?
6145 MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED :
6146 MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED;
6147
6148 snapshot_value = mgmt_rx_reo_sim_get_snapshot_value(
6149 frame_hw->params.global_timestamp,
6150 frame_hw->params.mgmt_pkt_ctr);
6151
6152 status = mgmt_rx_reo_sim_write_snapshot(
6153 link_id, ml_grp_id,
6154 snapshot_id, snapshot_value);
6155
6156 if (QDF_IS_STATUS_ERROR(status)) {
6157 mgmt_rx_reo_err("FW-%d : Failed to write snapshot %d",
6158 link_id, snapshot_id);
6159 goto error_free_fw_frame;
6160 }
6161
6162 status = qdf_create_work(NULL, &frame_fw->frame_handler_host,
6163 mgmt_rx_reo_sim_frame_handler_host, frame_fw);
6164 if (QDF_IS_STATUS_ERROR(status)) {
6165 mgmt_rx_reo_err("FW-%d : Failed to create work", link_id);
6166 goto error_free_fw_frame;
6167 }
6168
6169 ret = qdf_queue_work(
6170 NULL, sim_context->host_mgmt_frame_handler[link_id],
6171 &frame_fw->frame_handler_host);
6172 if (!ret) {
6173 mgmt_rx_reo_err("FW-%d : Work is already present on the queue",
6174 link_id);
6175 goto error_free_fw_frame;
6176 }
6177
6178 qdf_mem_free(frame_hw);
6179
6180 return;
6181
6182 error_free_fw_frame:
6183 qdf_mem_free(frame_fw);
6184 error_free_mac_hw_frame:
6185 qdf_mem_free(frame_hw);
6186
6187 mgmt_rx_reo_err("FW-%d : Exiting fw frame handler due to error",
6188 link_id);
6189 }
6190
6191 /**
6192 * mgmt_rx_reo_sim_get_link_id() - Helper API to get the link id value
6193 * from the index to the valid link list
6194 * @valid_link_list_index: Index to list of valid links
6195 *
6196 * Return: link id
6197 */
6198 static int8_t
mgmt_rx_reo_sim_get_link_id(uint8_t valid_link_list_index)6199 mgmt_rx_reo_sim_get_link_id(uint8_t valid_link_list_index)
6200 {
6201 struct mgmt_rx_reo_sim_context *sim_context;
6202
6203 if (valid_link_list_index >= MAX_MLO_LINKS) {
6204 mgmt_rx_reo_err("Invalid index %u to valid link list",
6205 valid_link_list_index);
6206 return MGMT_RX_REO_INVALID_LINK;
6207 }
6208
6209 sim_context = mgmt_rx_reo_sim_get_context();
6210 if (!sim_context) {
6211 mgmt_rx_reo_err("Mgmt reo simulation context is null");
6212 return MGMT_RX_REO_INVALID_LINK;
6213 }
6214
6215 return sim_context->link_id_to_pdev_map.valid_link_list
6216 [valid_link_list_index];
6217 }
6218
6219 /**
6220 * mgmt_rx_reo_sim_receive_from_air() - Simulate management frame reception from
6221 * the air
6222 * @mac_hw: pointer to structure representing MAC HW
6223 * @num_mlo_links: number of MLO HW links
6224 * @frame: pointer to management frame parameters
6225 *
6226 * This API simulates the management frame reception from air.
6227 *
6228 * Return: QDF_STATUS
6229 */
6230 static QDF_STATUS
mgmt_rx_reo_sim_receive_from_air(struct mgmt_rx_reo_sim_mac_hw * mac_hw,uint8_t num_mlo_links,struct mgmt_rx_frame_params * frame)6231 mgmt_rx_reo_sim_receive_from_air(struct mgmt_rx_reo_sim_mac_hw *mac_hw,
6232 uint8_t num_mlo_links,
6233 struct mgmt_rx_frame_params *frame)
6234 {
6235 uint8_t valid_link_list_index;
6236 int8_t link_id;
6237
6238 if (!mac_hw) {
6239 mgmt_rx_reo_err("pointer to MAC HW struct is null");
6240 return QDF_STATUS_E_NULL_VALUE;
6241 }
6242
6243 if (num_mlo_links == 0 || num_mlo_links > MAX_MLO_LINKS) {
6244 mgmt_rx_reo_err("Invalid number of MLO links %u",
6245 num_mlo_links);
6246 return QDF_STATUS_E_INVAL;
6247 }
6248
6249 if (!frame) {
6250 mgmt_rx_reo_err("pointer to frame parameters is null");
6251 return QDF_STATUS_E_NULL_VALUE;
6252 }
6253
6254 valid_link_list_index = mgmt_rx_reo_sim_get_random_unsigned_int(
6255 num_mlo_links);
6256 link_id = mgmt_rx_reo_sim_get_link_id(valid_link_list_index);
6257 qdf_assert_always(link_id >= 0);
6258 qdf_assert_always(link_id < MAX_MLO_LINKS);
6259
6260 frame->global_timestamp = div_u64(ktime_get_ns(), NSEC_PER_USEC);
6261 frame->mgmt_pkt_ctr = ++mac_hw->mgmt_pkt_ctr[link_id];
6262 frame->link_id = link_id;
6263
6264 return QDF_STATUS_SUCCESS;
6265 }
6266
6267 /**
6268 * mgmt_rx_reo_sim_undo_receive_from_air() - API to restore the state of MAC
6269 * HW in case of any Rx error.
6270 * @mac_hw: pointer to structure representing MAC HW
6271 * @frame: pointer to management frame parameters
6272 *
6273 * Return: QDF_STATUS
6274 */
6275 static QDF_STATUS
mgmt_rx_reo_sim_undo_receive_from_air(struct mgmt_rx_reo_sim_mac_hw * mac_hw,struct mgmt_rx_frame_params * frame)6276 mgmt_rx_reo_sim_undo_receive_from_air(struct mgmt_rx_reo_sim_mac_hw *mac_hw,
6277 struct mgmt_rx_frame_params *frame)
6278 {
6279 if (!mac_hw) {
6280 mgmt_rx_reo_err("pointer to MAC HW struct is null");
6281 return QDF_STATUS_E_NULL_VALUE;
6282 }
6283
6284 if (!frame) {
6285 mgmt_rx_reo_err("pointer to frame parameters is null");
6286 return QDF_STATUS_E_NULL_VALUE;
6287 }
6288
6289 if (frame->link_id >= MAX_MLO_LINKS) {
6290 mgmt_rx_reo_err("Invalid link id %u", frame->link_id);
6291 return QDF_STATUS_E_INVAL;
6292 }
6293
6294 --mac_hw->mgmt_pkt_ctr[frame->link_id];
6295
6296 return QDF_STATUS_SUCCESS;
6297 }
6298
6299 /**
6300 * mgmt_rx_reo_sim_mac_hw_thread() - kthread to simulate MAC HW
6301 * @data: pointer to data input
6302 *
6303 * kthread handler to simulate MAC HW.
6304 *
6305 * Return: 0 for success, else failure
6306 */
6307 static int
mgmt_rx_reo_sim_mac_hw_thread(void * data)6308 mgmt_rx_reo_sim_mac_hw_thread(void *data)
6309 {
6310 struct mgmt_rx_reo_sim_context *sim_context = data;
6311 struct mgmt_rx_reo_sim_mac_hw *mac_hw;
6312
6313 if (!sim_context) {
6314 mgmt_rx_reo_err("HW: Mgmt rx reo simulation context is null");
6315 return -EINVAL;
6316 }
6317
6318 mac_hw = &sim_context->mac_hw_sim.mac_hw_info;
6319
6320 while (!qdf_thread_should_stop()) {
6321 uint32_t inter_frame_delay_us;
6322 struct mgmt_rx_frame_params frame;
6323 struct mgmt_rx_frame_mac_hw *frame_mac_hw;
6324 int8_t link_id = -1;
6325 QDF_STATUS status;
6326 enum mgmt_rx_reo_shared_snapshot_id snapshot_id;
6327 struct mgmt_rx_reo_shared_snapshot snapshot_value;
6328 int8_t num_mlo_links;
6329 bool ret;
6330 uint8_t ml_grp_id;
6331
6332 num_mlo_links = mgmt_rx_reo_sim_get_num_mlo_links(sim_context);
6333 if (num_mlo_links < 0 ||
6334 num_mlo_links > MAX_MLO_LINKS) {
6335 mgmt_rx_reo_err("Invalid number of MLO links %d",
6336 num_mlo_links);
6337 qdf_assert_always(0);
6338 }
6339
6340 status = mgmt_rx_reo_sim_receive_from_air(mac_hw, num_mlo_links,
6341 &frame);
6342 if (QDF_IS_STATUS_ERROR(status)) {
6343 mgmt_rx_reo_err("Receive from the air failed");
6344 /**
6345 * Frame reception failed and we are not sure about the
6346 * link id. Without link id there is no way to restore
6347 * the mac hw state. Hence assert unconditionally.
6348 */
6349 qdf_assert_always(0);
6350 }
6351 link_id = frame.link_id;
6352
6353 mgmt_rx_reo_debug("HW-%d: received frame with ts = %u, ctr = %u",
6354 link_id, frame.global_timestamp,
6355 frame.mgmt_pkt_ctr);
6356
6357 frame_mac_hw = qdf_mem_malloc(sizeof(*frame_mac_hw));
6358 if (!frame_mac_hw) {
6359 mgmt_rx_reo_err("HW-%d: Failed to alloc mac hw frame",
6360 link_id);
6361
6362 /* Cleanup */
6363 status = mgmt_rx_reo_sim_undo_receive_from_air(
6364 mac_hw, &frame);
6365 qdf_assert_always(QDF_IS_STATUS_SUCCESS(status));
6366
6367 continue;
6368 }
6369
6370 frame_mac_hw->params = frame;
6371 frame_mac_hw->sim_context = sim_context;
6372 ml_grp_id = sim_context->ml_grp_id;
6373
6374 status = mgmt_rx_reo_sim_add_frame_to_pending_list(
6375 &sim_context->master_frame_list, &frame);
6376 if (QDF_IS_STATUS_ERROR(status)) {
6377 mgmt_rx_reo_err("HW-%d: Failed to add frame to list",
6378 link_id);
6379
6380 /* Cleanup */
6381 status = mgmt_rx_reo_sim_undo_receive_from_air(
6382 mac_hw, &frame);
6383 qdf_assert_always(QDF_IS_STATUS_SUCCESS(status));
6384
6385 qdf_mem_free(frame_mac_hw);
6386
6387 continue;
6388 }
6389
6390 snapshot_id = MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW;
6391 snapshot_value = mgmt_rx_reo_sim_get_snapshot_value(
6392 frame.global_timestamp,
6393 frame.mgmt_pkt_ctr);
6394
6395 status = mgmt_rx_reo_sim_write_snapshot(
6396 link_id, ml_grp_id
6397 snapshot_id, snapshot_value);
6398 if (QDF_IS_STATUS_ERROR(status)) {
6399 mgmt_rx_reo_err("HW-%d : Failed to write snapshot %d",
6400 link_id, snapshot_id);
6401
6402 /* Cleanup */
6403 status = mgmt_rx_reo_sim_remove_frame_from_pending_list(
6404 &sim_context->master_frame_list, &frame);
6405 qdf_assert_always(QDF_IS_STATUS_SUCCESS(status));
6406
6407 status = mgmt_rx_reo_sim_undo_receive_from_air(
6408 mac_hw, &frame);
6409 qdf_assert_always(QDF_IS_STATUS_SUCCESS(status));
6410
6411 qdf_mem_free(frame_mac_hw);
6412
6413 continue;
6414 }
6415
6416 status = qdf_create_work(NULL, &frame_mac_hw->frame_handler_fw,
6417 mgmt_rx_reo_sim_frame_handler_fw,
6418 frame_mac_hw);
6419 if (QDF_IS_STATUS_ERROR(status)) {
6420 mgmt_rx_reo_err("HW-%d : Failed to create work",
6421 link_id);
6422 qdf_assert_always(0);
6423 }
6424
6425 ret = qdf_queue_work(
6426 NULL, sim_context->fw_mgmt_frame_handler[link_id],
6427 &frame_mac_hw->frame_handler_fw);
6428 if (!ret) {
6429 mgmt_rx_reo_err("HW-%d : Work is already present in Q",
6430 link_id);
6431 qdf_assert_always(0);
6432 }
6433
6434 inter_frame_delay_us = MGMT_RX_REO_SIM_INTER_FRAME_DELAY_MIN +
6435 mgmt_rx_reo_sim_get_random_unsigned_int(
6436 MGMT_RX_REO_SIM_INTER_FRAME_DELAY_MIN_MAX_DELTA);
6437
6438 mgmt_rx_reo_sim_sleep(inter_frame_delay_us);
6439 }
6440
6441 return 0;
6442 }
6443
6444 /**
6445 * mgmt_rx_reo_sim_init_master_frame_list() - Initializes the master
6446 * management frame list
6447 * @master_frame_list: Pointer to master frame list
6448 *
6449 * This API initializes the master management frame list
6450 *
6451 * Return: QDF_STATUS
6452 */
6453 static QDF_STATUS
mgmt_rx_reo_sim_init_master_frame_list(struct mgmt_rx_reo_master_frame_list * master_frame_list)6454 mgmt_rx_reo_sim_init_master_frame_list(
6455 struct mgmt_rx_reo_master_frame_list *master_frame_list)
6456 {
6457 qdf_spinlock_create(&master_frame_list->lock);
6458
6459 qdf_list_create(&master_frame_list->pending_list,
6460 MGMT_RX_REO_SIM_PENDING_FRAME_LIST_MAX_SIZE);
6461 qdf_list_create(&master_frame_list->stale_list,
6462 MGMT_RX_REO_SIM_STALE_FRAME_LIST_MAX_SIZE);
6463
6464 return QDF_STATUS_SUCCESS;
6465 }
6466
6467 /**
6468 * mgmt_rx_reo_sim_deinit_master_frame_list() - De initializes the master
6469 * management frame list
6470 * @master_frame_list: Pointer to master frame list
6471 *
6472 * This API de initializes the master management frame list
6473 *
6474 * Return: QDF_STATUS
6475 */
6476 static QDF_STATUS
mgmt_rx_reo_sim_deinit_master_frame_list(struct mgmt_rx_reo_master_frame_list * master_frame_list)6477 mgmt_rx_reo_sim_deinit_master_frame_list(
6478 struct mgmt_rx_reo_master_frame_list *master_frame_list)
6479 {
6480 qdf_spin_lock(&master_frame_list->lock);
6481 qdf_list_destroy(&master_frame_list->stale_list);
6482 qdf_list_destroy(&master_frame_list->pending_list);
6483 qdf_spin_unlock(&master_frame_list->lock);
6484
6485 qdf_spinlock_destroy(&master_frame_list->lock);
6486
6487 return QDF_STATUS_SUCCESS;
6488 }
6489
6490 /**
6491 * mgmt_rx_reo_sim_generate_unique_link_id() - Helper API to generate
6492 * unique link id values
6493 * @link_id_to_pdev_map: pointer to link id to pdev map
6494 * @link_id: Pointer to unique link id
6495 *
6496 * This API generates unique link id values for each pdev. This API should be
6497 * called after acquiring the spin lock protecting link id to pdev map.
6498 *
6499 * Return: QDF_STATUS
6500 */
6501 static QDF_STATUS
mgmt_rx_reo_sim_generate_unique_link_id(struct wlan_objmgr_pdev ** link_id_to_pdev_map,uint8_t * link_id)6502 mgmt_rx_reo_sim_generate_unique_link_id(
6503 struct wlan_objmgr_pdev **link_id_to_pdev_map, uint8_t *link_id)
6504 {
6505 uint8_t random_link_id;
6506 uint8_t link;
6507
6508 if (!link_id_to_pdev_map || !link_id)
6509 return QDF_STATUS_E_NULL_VALUE;
6510
6511 for (link = 0; link < MAX_MLO_LINKS; link++)
6512 if (!link_id_to_pdev_map[link])
6513 break;
6514
6515 if (link == MAX_MLO_LINKS) {
6516 mgmt_rx_reo_err("All link ids are already allocated");
6517 return QDF_STATUS_E_FAILURE;
6518 }
6519
6520 while (1) {
6521 random_link_id = mgmt_rx_reo_sim_get_random_unsigned_int(
6522 MAX_MLO_LINKS);
6523
6524 if (!link_id_to_pdev_map[random_link_id])
6525 break;
6526 }
6527
6528 *link_id = random_link_id;
6529
6530 return QDF_STATUS_SUCCESS;
6531 }
6532
6533 /**
6534 * mgmt_rx_reo_sim_insert_into_link_id_to_pdev_map() - Builds the MLO HW link id
6535 * to pdev map
6536 * @link_id_to_pdev_map: pointer to link id to pdev map
6537 * @pdev: pointer to pdev object
6538 *
6539 * This API incrementally builds the MLO HW link id to pdev map. This API is
6540 * used only for simulation.
6541 *
6542 * Return: QDF_STATUS
6543 */
6544 static QDF_STATUS
mgmt_rx_reo_sim_insert_into_link_id_to_pdev_map(struct mgmt_rx_reo_sim_link_id_to_pdev_map * link_id_to_pdev_map,struct wlan_objmgr_pdev * pdev)6545 mgmt_rx_reo_sim_insert_into_link_id_to_pdev_map(
6546 struct mgmt_rx_reo_sim_link_id_to_pdev_map *link_id_to_pdev_map,
6547 struct wlan_objmgr_pdev *pdev)
6548 {
6549 uint8_t link_id;
6550 QDF_STATUS status;
6551
6552 if (!link_id_to_pdev_map) {
6553 mgmt_rx_reo_err("Link id to pdev map is null");
6554 return QDF_STATUS_E_NULL_VALUE;
6555 }
6556
6557 if (!pdev) {
6558 mgmt_rx_reo_err("pdev is null");
6559 return QDF_STATUS_E_NULL_VALUE;
6560 }
6561
6562 qdf_spin_lock(&link_id_to_pdev_map->lock);
6563
6564 status = mgmt_rx_reo_sim_generate_unique_link_id(
6565 link_id_to_pdev_map->map, &link_id);
6566 if (QDF_IS_STATUS_ERROR(status)) {
6567 qdf_spin_unlock(&link_id_to_pdev_map->lock);
6568 return QDF_STATUS_E_FAILURE;
6569 }
6570 qdf_assert_always(link_id < MAX_MLO_LINKS);
6571
6572 link_id_to_pdev_map->map[link_id] = pdev;
6573 link_id_to_pdev_map->valid_link_list
6574 [link_id_to_pdev_map->num_mlo_links] = link_id;
6575 link_id_to_pdev_map->num_mlo_links++;
6576
6577 qdf_spin_unlock(&link_id_to_pdev_map->lock);
6578
6579 return QDF_STATUS_SUCCESS;
6580 }
6581
6582 /**
6583 * mgmt_rx_reo_sim_remove_from_link_id_to_pdev_map() - Destroys the MLO HW link
6584 * id to pdev map
6585 * @link_id_to_pdev_map: pointer to link id to pdev map
6586 * @pdev: pointer to pdev object
6587 *
6588 * This API incrementally destroys the MLO HW link id to pdev map. This API is
6589 * used only for simulation.
6590 *
6591 * Return: QDF_STATUS
6592 */
6593 static QDF_STATUS
mgmt_rx_reo_sim_remove_from_link_id_to_pdev_map(struct mgmt_rx_reo_sim_link_id_to_pdev_map * link_id_to_pdev_map,struct wlan_objmgr_pdev * pdev)6594 mgmt_rx_reo_sim_remove_from_link_id_to_pdev_map(
6595 struct mgmt_rx_reo_sim_link_id_to_pdev_map *link_id_to_pdev_map,
6596 struct wlan_objmgr_pdev *pdev)
6597 {
6598 uint8_t link_id;
6599
6600 if (!link_id_to_pdev_map) {
6601 mgmt_rx_reo_err("Link id to pdev map is null");
6602 return QDF_STATUS_E_NULL_VALUE;
6603 }
6604
6605 if (!pdev) {
6606 mgmt_rx_reo_err("pdev is null");
6607 return QDF_STATUS_E_NULL_VALUE;
6608 }
6609
6610 qdf_spin_lock(&link_id_to_pdev_map->lock);
6611
6612 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
6613 if (link_id_to_pdev_map->map[link_id] == pdev) {
6614 link_id_to_pdev_map->map[link_id] = NULL;
6615 qdf_spin_unlock(&link_id_to_pdev_map->lock);
6616
6617 return QDF_STATUS_SUCCESS;
6618 }
6619 }
6620
6621 qdf_spin_unlock(&link_id_to_pdev_map->lock);
6622
6623 mgmt_rx_reo_err("Pdev %pK is not found in map", pdev);
6624
6625 return QDF_STATUS_E_FAILURE;
6626 }
6627
6628 QDF_STATUS
mgmt_rx_reo_sim_pdev_object_create_notification(struct wlan_objmgr_pdev * pdev)6629 mgmt_rx_reo_sim_pdev_object_create_notification(struct wlan_objmgr_pdev *pdev)
6630 {
6631 struct mgmt_rx_reo_sim_context *sim_context;
6632 QDF_STATUS status;
6633
6634 sim_context = mgmt_rx_reo_sim_get_context();
6635 if (!sim_context) {
6636 mgmt_rx_reo_err("Mgmt simulation context is null");
6637 return QDF_STATUS_E_NULL_VALUE;
6638 }
6639
6640 status = mgmt_rx_reo_sim_insert_into_link_id_to_pdev_map(
6641 &sim_context->link_id_to_pdev_map, pdev);
6642
6643 if (QDF_IS_STATUS_ERROR(status)) {
6644 mgmt_rx_reo_err("Failed to add pdev to the map %pK", pdev);
6645 return status;
6646 }
6647
6648 return QDF_STATUS_SUCCESS;
6649 }
6650
6651 QDF_STATUS
mgmt_rx_reo_sim_pdev_object_destroy_notification(struct wlan_objmgr_pdev * pdev)6652 mgmt_rx_reo_sim_pdev_object_destroy_notification(struct wlan_objmgr_pdev *pdev)
6653 {
6654 struct mgmt_rx_reo_sim_context *sim_context;
6655 QDF_STATUS status;
6656
6657 sim_context = mgmt_rx_reo_sim_get_context();
6658 if (!sim_context) {
6659 mgmt_rx_reo_err("Mgmt simulation context is null");
6660 return QDF_STATUS_E_NULL_VALUE;
6661 }
6662
6663 status = mgmt_rx_reo_sim_remove_from_link_id_to_pdev_map(
6664 &sim_context->link_id_to_pdev_map, pdev);
6665
6666 if (QDF_IS_STATUS_ERROR(status)) {
6667 mgmt_rx_reo_err("Failed to remove pdev from the map");
6668 return status;
6669 }
6670
6671 return QDF_STATUS_SUCCESS;
6672 }
6673
6674 QDF_STATUS
mgmt_rx_reo_sim_start(uint8_t ml_grp_id)6675 mgmt_rx_reo_sim_start(uint8_t ml_grp_id)
6676 {
6677 struct mgmt_rx_reo_context *reo_context;
6678 struct mgmt_rx_reo_sim_context *sim_context;
6679 qdf_thread_t *mac_hw_thread;
6680 uint8_t link_id;
6681 uint8_t id;
6682 QDF_STATUS status;
6683
6684 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
6685 if (!reo_context) {
6686 mgmt_rx_reo_err("reo context is null");
6687 return QDF_STATUS_E_NULL_VALUE;
6688 }
6689
6690 reo_context->simulation_in_progress = true;
6691
6692 sim_context = &reo_context->sim_context;
6693
6694 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
6695 struct workqueue_struct *wq;
6696
6697 wq = alloc_ordered_workqueue("mgmt_rx_reo_sim_host-%u", 0,
6698 link_id);
6699 if (!wq) {
6700 mgmt_rx_reo_err("Host workqueue creation failed");
6701 status = QDF_STATUS_E_FAILURE;
6702 goto error_destroy_fw_and_host_work_queues_till_last_link;
6703 }
6704 sim_context->host_mgmt_frame_handler[link_id] = wq;
6705
6706 wq = alloc_ordered_workqueue("mgmt_rx_reo_sim_fw-%u", 0,
6707 link_id);
6708 if (!wq) {
6709 mgmt_rx_reo_err("FW workqueue creation failed");
6710 status = QDF_STATUS_E_FAILURE;
6711 goto error_destroy_host_work_queue_of_last_link;
6712 }
6713 sim_context->fw_mgmt_frame_handler[link_id] = wq;
6714 }
6715
6716 mac_hw_thread = qdf_create_thread(mgmt_rx_reo_sim_mac_hw_thread,
6717 sim_context, "MAC_HW_thread");
6718 if (!mac_hw_thread) {
6719 mgmt_rx_reo_err("MAC HW thread creation failed");
6720 status = QDF_STATUS_E_FAILURE;
6721 goto error_destroy_fw_and_host_work_queues_of_last_link;
6722 }
6723
6724 sim_context->mac_hw_sim.mac_hw_thread = mac_hw_thread;
6725
6726 qdf_wake_up_process(sim_context->mac_hw_sim.mac_hw_thread);
6727
6728 return QDF_STATUS_SUCCESS;
6729
6730 error_destroy_fw_and_host_work_queues_of_last_link:
6731 drain_workqueue(sim_context->fw_mgmt_frame_handler[link_id]);
6732 destroy_workqueue(sim_context->fw_mgmt_frame_handler[link_id]);
6733
6734 error_destroy_host_work_queue_of_last_link:
6735 drain_workqueue(sim_context->host_mgmt_frame_handler[link_id]);
6736 destroy_workqueue(sim_context->host_mgmt_frame_handler[link_id]);
6737
6738 error_destroy_fw_and_host_work_queues_till_last_link:
6739 for (id = 0; id < link_id; id++) {
6740 drain_workqueue(sim_context->fw_mgmt_frame_handler[id]);
6741 destroy_workqueue(sim_context->fw_mgmt_frame_handler[id]);
6742
6743 drain_workqueue(sim_context->host_mgmt_frame_handler[id]);
6744 destroy_workqueue(sim_context->host_mgmt_frame_handler[id]);
6745 }
6746
6747 return status;
6748 }
6749
6750 QDF_STATUS
mgmt_rx_reo_sim_stop(uint8_t ml_grp_id)6751 mgmt_rx_reo_sim_stop(uint8_t ml_grp_id)
6752 {
6753 struct mgmt_rx_reo_context *reo_context;
6754 struct mgmt_rx_reo_sim_context *sim_context;
6755 struct mgmt_rx_reo_master_frame_list *master_frame_list;
6756 uint8_t link_id;
6757 QDF_STATUS status;
6758
6759 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
6760 if (!reo_context) {
6761 mgmt_rx_reo_err("reo context is null");
6762 return QDF_STATUS_E_NULL_VALUE;
6763 }
6764
6765 sim_context = &reo_context->sim_context;
6766
6767 status = qdf_thread_join(sim_context->mac_hw_sim.mac_hw_thread);
6768 if (QDF_IS_STATUS_ERROR(status)) {
6769 mgmt_rx_reo_err("Failed to stop the thread");
6770 return status;
6771 }
6772
6773 sim_context->mac_hw_sim.mac_hw_thread = NULL;
6774
6775 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++) {
6776 /* Wait for all the pending frames to be processed by FW */
6777 drain_workqueue(sim_context->fw_mgmt_frame_handler[link_id]);
6778 destroy_workqueue(sim_context->fw_mgmt_frame_handler[link_id]);
6779
6780 /* Wait for all the pending frames to be processed by host */
6781 drain_workqueue(sim_context->host_mgmt_frame_handler[link_id]);
6782 destroy_workqueue(
6783 sim_context->host_mgmt_frame_handler[link_id]);
6784 }
6785
6786 status = mgmt_rx_reo_print_ingress_frame_info
6787 (MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_PRINT_MAX_FRAMES);
6788 if (QDF_IS_STATUS_ERROR(status)) {
6789 mgmt_rx_reo_err("Failed to print ingress frame debug info");
6790 return status;
6791 }
6792
6793 status = mgmt_rx_reo_print_egress_frame_info
6794 (MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_PRINT_MAX_FRAMES);
6795 if (QDF_IS_STATUS_ERROR(status)) {
6796 mgmt_rx_reo_err("Failed to print egress frame debug info");
6797 return status;
6798 }
6799
6800 master_frame_list = &sim_context->master_frame_list;
6801 if (!qdf_list_empty(&master_frame_list->pending_list) ||
6802 !qdf_list_empty(&master_frame_list->stale_list)) {
6803 mgmt_rx_reo_err("reo sim failure: pending/stale frame list non empty");
6804
6805 status = mgmt_rx_reo_list_display(&reo_context->reo_list);
6806 if (QDF_IS_STATUS_ERROR(status)) {
6807 mgmt_rx_reo_err("Failed to print reorder list");
6808 return status;
6809 }
6810
6811 qdf_assert_always(0);
6812 } else {
6813 mgmt_rx_reo_err("reo sim passed");
6814 }
6815
6816 reo_context->simulation_in_progress = false;
6817
6818 return QDF_STATUS_SUCCESS;
6819 }
6820
6821 /**
6822 * mgmt_rx_reo_sim_init() - Initialize management rx reorder simulation
6823 * context.
6824 * @reo_context: Pointer to reo context
6825 *
6826 * Return: QDF_STATUS of operation
6827 */
6828 static QDF_STATUS
mgmt_rx_reo_sim_init(struct mgmt_rx_reo_context * reo_context)6829 mgmt_rx_reo_sim_init(struct mgmt_rx_reo_context *reo_context)
6830 {
6831 QDF_STATUS status;
6832 struct mgmt_rx_reo_sim_context *sim_context;
6833 uint8_t link_id;
6834
6835 if (!reo_context) {
6836 mgmt_rx_reo_err("reo context is null");
6837 return QDF_STATUS_E_NULL_VALUE;
6838 }
6839
6840 sim_context = &reo_context->sim_context;
6841
6842 qdf_mem_zero(sim_context, sizeof(*sim_context));
6843 sim_context->mlo_grp_id = reo_context->mlo_grp_id;
6844
6845 status = mgmt_rx_reo_sim_init_master_frame_list(
6846 &sim_context->master_frame_list);
6847 if (QDF_IS_STATUS_ERROR(status)) {
6848 mgmt_rx_reo_err("Failed to create master mgmt frame list");
6849 return status;
6850 }
6851
6852 qdf_spinlock_create(&sim_context->link_id_to_pdev_map.lock);
6853
6854 for (link_id = 0; link_id < MAX_MLO_LINKS; link_id++)
6855 sim_context->link_id_to_pdev_map.valid_link_list[link_id] =
6856 MGMT_RX_REO_INVALID_LINK;
6857
6858 return QDF_STATUS_SUCCESS;
6859 }
6860
6861 /**
6862 * mgmt_rx_reo_sim_deinit() - De initialize management rx reorder simulation
6863 * context.
6864 * @reo_context: Pointer to reo context
6865 *
6866 * Return: QDF_STATUS of operation
6867 */
6868 static QDF_STATUS
mgmt_rx_reo_sim_deinit(struct mgmt_rx_reo_context * reo_context)6869 mgmt_rx_reo_sim_deinit(struct mgmt_rx_reo_context *reo_context)
6870 {
6871 QDF_STATUS status;
6872 struct mgmt_rx_reo_sim_context *sim_context;
6873
6874 if (!reo_context) {
6875 mgmt_rx_reo_err("reo context is null");
6876 return QDF_STATUS_E_NULL_VALUE;
6877 }
6878
6879 sim_context = &reo_context->sim_context;
6880
6881 qdf_spinlock_destroy(&sim_context->link_id_to_pdev_map.lock);
6882
6883 status = mgmt_rx_reo_sim_deinit_master_frame_list(
6884 &sim_context->master_frame_list);
6885 if (QDF_IS_STATUS_ERROR(status)) {
6886 mgmt_rx_reo_err("Failed to destroy master frame list");
6887 return status;
6888 }
6889
6890 return QDF_STATUS_SUCCESS;
6891 }
6892
6893 QDF_STATUS
mgmt_rx_reo_sim_get_snapshot_address(struct wlan_objmgr_pdev * pdev,enum mgmt_rx_reo_shared_snapshot_id id,struct mgmt_rx_reo_shared_snapshot ** address)6894 mgmt_rx_reo_sim_get_snapshot_address(
6895 struct wlan_objmgr_pdev *pdev,
6896 enum mgmt_rx_reo_shared_snapshot_id id,
6897 struct mgmt_rx_reo_shared_snapshot **address)
6898 {
6899 int8_t link_id;
6900 struct mgmt_rx_reo_sim_context *sim_context;
6901
6902 sim_context = mgmt_rx_reo_sim_get_context();
6903 if (!sim_context) {
6904 mgmt_rx_reo_err("Mgmt reo simulation context is null");
6905 return QDF_STATUS_E_NULL_VALUE;
6906 }
6907
6908 if (!pdev) {
6909 mgmt_rx_reo_err("pdev is NULL");
6910 return QDF_STATUS_E_NULL_VALUE;
6911 }
6912
6913 if (id < 0 || id >= MGMT_RX_REO_SHARED_SNAPSHOT_MAX) {
6914 mgmt_rx_reo_err("Invalid snapshot ID %d", id);
6915 return QDF_STATUS_E_INVAL;
6916 }
6917
6918 if (!address) {
6919 mgmt_rx_reo_err("Pointer to snapshot address is null");
6920 return QDF_STATUS_E_NULL_VALUE;
6921 }
6922
6923 link_id = wlan_get_mlo_link_id_from_pdev(pdev);
6924 if (link_id < 0 || link_id >= MAX_MLO_LINKS) {
6925 mgmt_rx_reo_err("Invalid link id %d for the pdev %pK", link_id,
6926 pdev);
6927 return QDF_STATUS_E_INVAL;
6928 }
6929
6930 *address = &sim_context->snapshot[link_id][id];
6931
6932 return QDF_STATUS_SUCCESS;
6933 }
6934 #endif /* WLAN_MGMT_RX_REO_SIM_SUPPORT */
6935
6936 #ifdef WLAN_MGMT_RX_REO_DEBUG_SUPPORT
6937 /**
6938 * mgmt_rx_reo_ingress_debug_info_init() - Initialize the management rx-reorder
6939 * ingress frame debug info
6940 * @psoc: Pointer to psoc
6941 * @ingress_debug_info_init_count: Initialization count
6942 * @ingress_frame_debug_info: Ingress frame debug info object
6943 *
6944 * API to initialize the management rx-reorder ingress frame debug info.
6945 *
6946 * Return: QDF_STATUS
6947 */
6948 static QDF_STATUS
mgmt_rx_reo_ingress_debug_info_init(struct wlan_objmgr_psoc * psoc,qdf_atomic_t * ingress_debug_info_init_count,struct reo_ingress_debug_info * ingress_frame_debug_info)6949 mgmt_rx_reo_ingress_debug_info_init
6950 (struct wlan_objmgr_psoc *psoc,
6951 qdf_atomic_t *ingress_debug_info_init_count,
6952 struct reo_ingress_debug_info *ingress_frame_debug_info)
6953 {
6954 if (!psoc) {
6955 mgmt_rx_reo_err("psoc is null");
6956 return QDF_STATUS_E_NULL_VALUE;
6957 }
6958
6959 if (!ingress_frame_debug_info) {
6960 mgmt_rx_reo_err("Ingress frame debug info is null");
6961 return QDF_STATUS_E_NULL_VALUE;
6962 }
6963
6964 /* We need to initialize only for the first invocation */
6965 if (qdf_atomic_read(ingress_debug_info_init_count))
6966 goto success;
6967
6968 ingress_frame_debug_info->frame_list_size =
6969 wlan_mgmt_rx_reo_get_ingress_frame_debug_list_size(psoc);
6970
6971 if (ingress_frame_debug_info->frame_list_size) {
6972 ingress_frame_debug_info->frame_list = qdf_mem_malloc
6973 (ingress_frame_debug_info->frame_list_size *
6974 sizeof(*ingress_frame_debug_info->frame_list));
6975
6976 if (!ingress_frame_debug_info->frame_list) {
6977 mgmt_rx_reo_err("Failed to allocate debug info");
6978 return QDF_STATUS_E_NOMEM;
6979 }
6980 }
6981
6982 /* Initialize the string for storing the debug info table boarder */
6983 qdf_mem_set(ingress_frame_debug_info->boarder,
6984 MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_BOARDER_MAX_SIZE, '-');
6985
6986 success:
6987 qdf_atomic_inc(ingress_debug_info_init_count);
6988 return QDF_STATUS_SUCCESS;
6989 }
6990
6991 /**
6992 * mgmt_rx_reo_egress_debug_info_init() - Initialize the management rx-reorder
6993 * egress frame debug info
6994 * @psoc: Pointer to psoc
6995 * @egress_debug_info_init_count: Initialization count
6996 * @egress_frame_debug_info: Egress frame debug info object
6997 *
6998 * API to initialize the management rx-reorder egress frame debug info.
6999 *
7000 * Return: QDF_STATUS
7001 */
7002 static QDF_STATUS
mgmt_rx_reo_egress_debug_info_init(struct wlan_objmgr_psoc * psoc,qdf_atomic_t * egress_debug_info_init_count,struct reo_egress_debug_info * egress_frame_debug_info)7003 mgmt_rx_reo_egress_debug_info_init
7004 (struct wlan_objmgr_psoc *psoc,
7005 qdf_atomic_t *egress_debug_info_init_count,
7006 struct reo_egress_debug_info *egress_frame_debug_info)
7007 {
7008 if (!psoc) {
7009 mgmt_rx_reo_err("psoc is null");
7010 return QDF_STATUS_E_NULL_VALUE;
7011 }
7012
7013 if (!egress_frame_debug_info) {
7014 mgmt_rx_reo_err("Egress frame debug info is null");
7015 return QDF_STATUS_E_NULL_VALUE;
7016 }
7017
7018 /* We need to initialize only for the first invocation */
7019 if (qdf_atomic_read(egress_debug_info_init_count))
7020 goto success;
7021
7022 egress_frame_debug_info->frame_list_size =
7023 wlan_mgmt_rx_reo_get_egress_frame_debug_list_size(psoc);
7024
7025 if (egress_frame_debug_info->frame_list_size) {
7026 egress_frame_debug_info->frame_list = qdf_mem_malloc
7027 (egress_frame_debug_info->frame_list_size *
7028 sizeof(*egress_frame_debug_info->frame_list));
7029
7030 if (!egress_frame_debug_info->frame_list) {
7031 mgmt_rx_reo_err("Failed to allocate debug info");
7032 return QDF_STATUS_E_NOMEM;
7033 }
7034 }
7035
7036 /* Initialize the string for storing the debug info table boarder */
7037 qdf_mem_set(egress_frame_debug_info->boarder,
7038 MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_BOARDER_MAX_SIZE, '-');
7039
7040 success:
7041 qdf_atomic_inc(egress_debug_info_init_count);
7042 return QDF_STATUS_SUCCESS;
7043 }
7044
7045 /**
7046 * mgmt_rx_reo_scheduler_debug_info_init() - Initialize the management
7047 * rx-reorder scheduler debug info
7048 * @psoc: Pointer to psoc
7049 * @scheduler_debug_info_init_count: Initialization count
7050 * @scheduler_debug_info: Scheduler debug info object
7051 *
7052 * API to initialize the management rx-reorder Scheduler debug info.
7053 *
7054 * Return: QDF_STATUS
7055 */
7056 static QDF_STATUS
mgmt_rx_reo_scheduler_debug_info_init(struct wlan_objmgr_psoc * psoc,qdf_atomic_t * scheduler_debug_info_init_count,struct reo_scheduler_debug_info * scheduler_debug_info)7057 mgmt_rx_reo_scheduler_debug_info_init
7058 (struct wlan_objmgr_psoc *psoc,
7059 qdf_atomic_t *scheduler_debug_info_init_count,
7060 struct reo_scheduler_debug_info *scheduler_debug_info)
7061 {
7062 if (!psoc) {
7063 mgmt_rx_reo_err("psoc is null");
7064 return QDF_STATUS_E_NULL_VALUE;
7065 }
7066
7067 if (!scheduler_debug_info) {
7068 mgmt_rx_reo_err("scheduler debug info is null");
7069 return QDF_STATUS_E_NULL_VALUE;
7070 }
7071
7072 /* We need to initialize only for the first invocation */
7073 if (qdf_atomic_read(scheduler_debug_info_init_count))
7074 goto success;
7075
7076 scheduler_debug_info->frame_list_size =
7077 wlan_mgmt_rx_reo_get_scheduler_debug_list_size(psoc);
7078
7079 if (scheduler_debug_info->frame_list_size) {
7080 scheduler_debug_info->frame_list = qdf_mem_malloc
7081 (scheduler_debug_info->frame_list_size *
7082 sizeof(*scheduler_debug_info->frame_list));
7083
7084 if (!scheduler_debug_info->frame_list) {
7085 mgmt_rx_reo_err("Failed to allocate debug info");
7086 return QDF_STATUS_E_NOMEM;
7087 }
7088 }
7089
7090 success:
7091 qdf_atomic_inc(scheduler_debug_info_init_count);
7092 return QDF_STATUS_SUCCESS;
7093 }
7094
7095 /**
7096 * mgmt_rx_reo_debug_info_init() - Initialize the management rx-reorder debug
7097 * info
7098 * @pdev: pointer to pdev object
7099 *
7100 * API to initialize the management rx-reorder debug info.
7101 *
7102 * Return: QDF_STATUS
7103 */
7104 static QDF_STATUS
mgmt_rx_reo_debug_info_init(struct wlan_objmgr_pdev * pdev)7105 mgmt_rx_reo_debug_info_init(struct wlan_objmgr_pdev *pdev)
7106 {
7107 struct mgmt_rx_reo_context *reo_context;
7108 QDF_STATUS status;
7109 struct wlan_objmgr_psoc *psoc;
7110
7111 psoc = wlan_pdev_get_psoc(pdev);
7112
7113 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_psoc(psoc))
7114 return QDF_STATUS_SUCCESS;
7115
7116 reo_context = wlan_mgmt_rx_reo_get_ctx_from_pdev(pdev);
7117 if (!reo_context) {
7118 mgmt_rx_reo_err("reo context is null");
7119 return QDF_STATUS_E_NULL_VALUE;
7120 }
7121
7122 status = mgmt_rx_reo_ingress_debug_info_init
7123 (psoc, &reo_context->ingress_debug_info_init_count,
7124 &reo_context->ingress_frame_debug_info);
7125 if (QDF_IS_STATUS_ERROR(status)) {
7126 mgmt_rx_reo_err("Failed to initialize ingress debug info");
7127 return QDF_STATUS_E_FAILURE;
7128 }
7129
7130 status = mgmt_rx_reo_egress_debug_info_init
7131 (psoc, &reo_context->egress_debug_info_init_count,
7132 &reo_context->egress_frame_debug_info);
7133 if (QDF_IS_STATUS_ERROR(status)) {
7134 mgmt_rx_reo_err("Failed to initialize egress debug info");
7135 return QDF_STATUS_E_FAILURE;
7136 }
7137
7138 status = mgmt_rx_reo_scheduler_debug_info_init
7139 (psoc, &reo_context->scheduler_debug_info_init_count,
7140 &reo_context->scheduler_debug_info);
7141 if (QDF_IS_STATUS_ERROR(status)) {
7142 mgmt_rx_reo_err("Failed to initialize scheduler debug info");
7143 return QDF_STATUS_E_FAILURE;
7144 }
7145
7146 return QDF_STATUS_SUCCESS;
7147 }
7148
7149 /**
7150 * mgmt_rx_reo_ingress_debug_info_deinit() - De initialize the management
7151 * rx-reorder ingress frame debug info
7152 * @psoc: Pointer to psoc
7153 * @ingress_debug_info_init_count: Initialization count
7154 * @ingress_frame_debug_info: Ingress frame debug info object
7155 *
7156 * API to de initialize the management rx-reorder ingress frame debug info.
7157 *
7158 * Return: QDF_STATUS
7159 */
7160 static QDF_STATUS
mgmt_rx_reo_ingress_debug_info_deinit(struct wlan_objmgr_psoc * psoc,qdf_atomic_t * ingress_debug_info_init_count,struct reo_ingress_debug_info * ingress_frame_debug_info)7161 mgmt_rx_reo_ingress_debug_info_deinit
7162 (struct wlan_objmgr_psoc *psoc,
7163 qdf_atomic_t *ingress_debug_info_init_count,
7164 struct reo_ingress_debug_info *ingress_frame_debug_info)
7165 {
7166 if (!psoc) {
7167 mgmt_rx_reo_err("psoc is null");
7168 return QDF_STATUS_E_NULL_VALUE;
7169 }
7170
7171 if (!ingress_frame_debug_info) {
7172 mgmt_rx_reo_err("Ingress frame debug info is null");
7173 return QDF_STATUS_E_NULL_VALUE;
7174 }
7175
7176 if (!qdf_atomic_read(ingress_debug_info_init_count)) {
7177 mgmt_rx_reo_err("Ingress debug info ref cnt is 0");
7178 return QDF_STATUS_E_FAILURE;
7179 }
7180
7181 /* We need to de-initialize only for the last invocation */
7182 if (qdf_atomic_dec_and_test(ingress_debug_info_init_count))
7183 goto success;
7184
7185 if (ingress_frame_debug_info->frame_list) {
7186 qdf_mem_free(ingress_frame_debug_info->frame_list);
7187 ingress_frame_debug_info->frame_list = NULL;
7188 }
7189 ingress_frame_debug_info->frame_list_size = 0;
7190
7191 qdf_mem_zero(ingress_frame_debug_info->boarder,
7192 MGMT_RX_REO_INGRESS_FRAME_DEBUG_INFO_BOARDER_MAX_SIZE + 1);
7193
7194 success:
7195 return QDF_STATUS_SUCCESS;
7196 }
7197
7198 /**
7199 * mgmt_rx_reo_egress_debug_info_deinit() - De initialize the management
7200 * rx-reorder egress frame debug info
7201 * @psoc: Pointer to psoc
7202 * @egress_debug_info_init_count: Initialization count
7203 * @egress_frame_debug_info: Egress frame debug info object
7204 *
7205 * API to de initialize the management rx-reorder egress frame debug info.
7206 *
7207 * Return: QDF_STATUS
7208 */
7209 static QDF_STATUS
mgmt_rx_reo_egress_debug_info_deinit(struct wlan_objmgr_psoc * psoc,qdf_atomic_t * egress_debug_info_init_count,struct reo_egress_debug_info * egress_frame_debug_info)7210 mgmt_rx_reo_egress_debug_info_deinit
7211 (struct wlan_objmgr_psoc *psoc,
7212 qdf_atomic_t *egress_debug_info_init_count,
7213 struct reo_egress_debug_info *egress_frame_debug_info)
7214 {
7215 if (!psoc) {
7216 mgmt_rx_reo_err("psoc is null");
7217 return QDF_STATUS_E_NULL_VALUE;
7218 }
7219
7220 if (!egress_frame_debug_info) {
7221 mgmt_rx_reo_err("Egress frame debug info is null");
7222 return QDF_STATUS_E_NULL_VALUE;
7223 }
7224
7225 if (!qdf_atomic_read(egress_debug_info_init_count)) {
7226 mgmt_rx_reo_err("Egress debug info ref cnt is 0");
7227 return QDF_STATUS_E_FAILURE;
7228 }
7229
7230 /* We need to de-initialize only for the last invocation */
7231 if (qdf_atomic_dec_and_test(egress_debug_info_init_count))
7232 goto success;
7233
7234 if (egress_frame_debug_info->frame_list) {
7235 qdf_mem_free(egress_frame_debug_info->frame_list);
7236 egress_frame_debug_info->frame_list = NULL;
7237 }
7238 egress_frame_debug_info->frame_list_size = 0;
7239
7240 qdf_mem_zero(egress_frame_debug_info->boarder,
7241 MGMT_RX_REO_EGRESS_FRAME_DEBUG_INFO_BOARDER_MAX_SIZE + 1);
7242
7243 success:
7244 return QDF_STATUS_SUCCESS;
7245 }
7246
7247 /**
7248 * mgmt_rx_reo_scheduler_debug_info_deinit() - De initialize the management
7249 * rx-reorder scheduler debug info
7250 * @psoc: Pointer to psoc
7251 * @scheduler_debug_info_init_count: Initialization count
7252 * @scheduler_debug_info: Scheduler debug info object
7253 *
7254 * API to de initialize the management rx-reorder scheduler debug info.
7255 *
7256 * Return: QDF_STATUS
7257 */
7258 static QDF_STATUS
mgmt_rx_reo_scheduler_debug_info_deinit(struct wlan_objmgr_psoc * psoc,qdf_atomic_t * scheduler_debug_info_init_count,struct reo_scheduler_debug_info * scheduler_debug_info)7259 mgmt_rx_reo_scheduler_debug_info_deinit
7260 (struct wlan_objmgr_psoc *psoc,
7261 qdf_atomic_t *scheduler_debug_info_init_count,
7262 struct reo_scheduler_debug_info *scheduler_debug_info)
7263 {
7264 if (!psoc) {
7265 mgmt_rx_reo_err("psoc is null");
7266 return QDF_STATUS_E_NULL_VALUE;
7267 }
7268
7269 if (!scheduler_debug_info) {
7270 mgmt_rx_reo_err("Scheduler debug info is null");
7271 return QDF_STATUS_E_NULL_VALUE;
7272 }
7273
7274 if (!qdf_atomic_read(scheduler_debug_info_init_count)) {
7275 mgmt_rx_reo_err("Scheduler debug info ref cnt is 0");
7276 return QDF_STATUS_E_FAILURE;
7277 }
7278
7279 /* We need to de-initialize only for the last invocation */
7280 if (qdf_atomic_dec_and_test(scheduler_debug_info_init_count))
7281 goto success;
7282
7283 if (scheduler_debug_info->frame_list) {
7284 qdf_mem_free(scheduler_debug_info->frame_list);
7285 scheduler_debug_info->frame_list = NULL;
7286 }
7287 scheduler_debug_info->frame_list_size = 0;
7288
7289 success:
7290 return QDF_STATUS_SUCCESS;
7291 }
7292
7293 /**
7294 * mgmt_rx_reo_debug_info_deinit() - De initialize the management rx-reorder
7295 * debug info
7296 * @pdev: Pointer to pdev object
7297 *
7298 * API to de initialize the management rx-reorder debug info.
7299 *
7300 * Return: QDF_STATUS
7301 */
7302 static QDF_STATUS
mgmt_rx_reo_debug_info_deinit(struct wlan_objmgr_pdev * pdev)7303 mgmt_rx_reo_debug_info_deinit(struct wlan_objmgr_pdev *pdev)
7304 {
7305 struct mgmt_rx_reo_context *reo_context;
7306 QDF_STATUS status;
7307 struct wlan_objmgr_psoc *psoc;
7308
7309 psoc = wlan_pdev_get_psoc(pdev);
7310
7311 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_psoc(psoc))
7312 return QDF_STATUS_SUCCESS;
7313
7314 reo_context = wlan_mgmt_rx_reo_get_ctx_from_pdev(pdev);
7315 if (!reo_context) {
7316 mgmt_rx_reo_err("reo context is null");
7317 return QDF_STATUS_E_NULL_VALUE;
7318 }
7319
7320 status = mgmt_rx_reo_ingress_debug_info_deinit
7321 (psoc, &reo_context->ingress_debug_info_init_count,
7322 &reo_context->ingress_frame_debug_info);
7323 if (QDF_IS_STATUS_ERROR(status)) {
7324 mgmt_rx_reo_err("Failed to deinitialize ingress debug info");
7325 return QDF_STATUS_E_FAILURE;
7326 }
7327
7328 status = mgmt_rx_reo_egress_debug_info_deinit
7329 (psoc, &reo_context->egress_debug_info_init_count,
7330 &reo_context->egress_frame_debug_info);
7331 if (QDF_IS_STATUS_ERROR(status)) {
7332 mgmt_rx_reo_err("Failed to deinitialize egress debug info");
7333 return QDF_STATUS_E_FAILURE;
7334 }
7335
7336 status = mgmt_rx_reo_scheduler_debug_info_deinit
7337 (psoc, &reo_context->scheduler_debug_info_init_count,
7338 &reo_context->scheduler_debug_info);
7339 if (QDF_IS_STATUS_ERROR(status)) {
7340 mgmt_rx_reo_err("Failed to deinitialize scheduler debug info");
7341 return QDF_STATUS_E_FAILURE;
7342 }
7343
7344 return QDF_STATUS_SUCCESS;
7345 }
7346 #else
7347 static QDF_STATUS
mgmt_rx_reo_debug_info_init(struct wlan_objmgr_pdev * pdev)7348 mgmt_rx_reo_debug_info_init(struct wlan_objmgr_pdev *pdev)
7349 {
7350 return QDF_STATUS_SUCCESS;
7351 }
7352
7353 static QDF_STATUS
mgmt_rx_reo_debug_info_deinit(struct wlan_objmgr_pdev * pdev)7354 mgmt_rx_reo_debug_info_deinit(struct wlan_objmgr_pdev *pdev)
7355 {
7356 return QDF_STATUS_SUCCESS;
7357 }
7358 #endif /* WLAN_MGMT_RX_REO_DEBUG_SUPPORT */
7359
7360 /**
7361 * mgmt_rx_reo_flush_list() - Flush all entries in the reorder list
7362 * @reo_list: Pointer to reorder list
7363 *
7364 * API to flush all the entries of the reorder list. This API would acquire
7365 * the lock protecting the list.
7366 *
7367 * Return: QDF_STATUS
7368 */
7369 static QDF_STATUS
mgmt_rx_reo_flush_list(struct mgmt_rx_reo_list * reo_list)7370 mgmt_rx_reo_flush_list(struct mgmt_rx_reo_list *reo_list)
7371 {
7372 struct mgmt_rx_reo_list_entry *cur_entry;
7373 struct mgmt_rx_reo_list_entry *temp;
7374
7375 if (!reo_list) {
7376 mgmt_rx_reo_err("reorder list is null");
7377 return QDF_STATUS_E_NULL_VALUE;
7378 }
7379
7380 qdf_spin_lock_bh(&reo_list->list_lock);
7381
7382 qdf_list_for_each_del(&reo_list->list, cur_entry, temp, node) {
7383 free_mgmt_rx_event_params(cur_entry->rx_params);
7384
7385 /**
7386 * Release the reference taken when the entry is inserted into
7387 * the reorder list.
7388 */
7389 wlan_objmgr_pdev_release_ref(cur_entry->pdev,
7390 WLAN_MGMT_RX_REO_ID);
7391
7392 qdf_mem_free(cur_entry);
7393 }
7394
7395 qdf_spin_unlock_bh(&reo_list->list_lock);
7396
7397 return QDF_STATUS_SUCCESS;
7398 }
7399
7400 /**
7401 * mgmt_rx_reo_ingress_list_deinit() - De initialize the management rx-reorder
7402 * ingress list
7403 * @ingress_list: Pointer to ingress reorder list
7404 *
7405 * API to de initialize the management rx-reorder ingress list.
7406 *
7407 * Return: QDF_STATUS
7408 */
7409 static QDF_STATUS
mgmt_rx_reo_ingress_list_deinit(struct mgmt_rx_reo_ingress_list * ingress_list)7410 mgmt_rx_reo_ingress_list_deinit(struct mgmt_rx_reo_ingress_list *ingress_list)
7411 {
7412 QDF_STATUS status;
7413 struct mgmt_rx_reo_list *reo_ingress_list;
7414
7415 if (!ingress_list) {
7416 mgmt_rx_reo_err("Ingress list is null");
7417 return QDF_STATUS_E_NULL_VALUE;
7418 }
7419 reo_ingress_list = &ingress_list->reo_list;
7420
7421 qdf_timer_sync_cancel(&ingress_list->ageout_timer);
7422 qdf_timer_free(&ingress_list->ageout_timer);
7423
7424 status = mgmt_rx_reo_flush_list(reo_ingress_list);
7425 if (QDF_IS_STATUS_ERROR(status)) {
7426 mgmt_rx_reo_err("Failed to flush the ingress list");
7427 return status;
7428 }
7429 qdf_spinlock_destroy(&reo_ingress_list->list_lock);
7430 qdf_list_destroy(&reo_ingress_list->list);
7431
7432 return QDF_STATUS_SUCCESS;
7433 }
7434
7435 /**
7436 * mgmt_rx_reo_egress_list_deinit() - De initialize the management rx-reorder
7437 * egress list
7438 * @egress_list: Pointer to egress reorder list
7439 *
7440 * API to de initialize the management rx-reorder egress list.
7441 *
7442 * Return: QDF_STATUS
7443 */
7444 static QDF_STATUS
mgmt_rx_reo_egress_list_deinit(struct mgmt_rx_reo_egress_list * egress_list)7445 mgmt_rx_reo_egress_list_deinit(struct mgmt_rx_reo_egress_list *egress_list)
7446 {
7447 QDF_STATUS status;
7448 struct mgmt_rx_reo_list *reo_egress_list;
7449
7450 if (!egress_list) {
7451 mgmt_rx_reo_err("Egress list is null");
7452 return QDF_STATUS_E_NULL_VALUE;
7453 }
7454 reo_egress_list = &egress_list->reo_list;
7455
7456 qdf_timer_sync_cancel(&egress_list->egress_inactivity_timer);
7457 qdf_timer_free(&egress_list->egress_inactivity_timer);
7458
7459 status = mgmt_rx_reo_flush_list(reo_egress_list);
7460 if (QDF_IS_STATUS_ERROR(status)) {
7461 mgmt_rx_reo_err("Failed to flush the egress list");
7462 return QDF_STATUS_E_FAILURE;
7463 }
7464 qdf_spinlock_destroy(&reo_egress_list->list_lock);
7465 qdf_list_destroy(&reo_egress_list->list);
7466
7467 return QDF_STATUS_SUCCESS;
7468 }
7469
7470 QDF_STATUS
mgmt_rx_reo_deinit_context(uint8_t ml_grp_id)7471 mgmt_rx_reo_deinit_context(uint8_t ml_grp_id)
7472 {
7473 QDF_STATUS status;
7474 struct mgmt_rx_reo_context *reo_context;
7475
7476 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
7477 if (!reo_context) {
7478 mgmt_rx_reo_err("reo context is null");
7479 return QDF_STATUS_E_NULL_VALUE;
7480 }
7481
7482 qdf_spinlock_destroy(&reo_context->frame_release_lock);
7483 qdf_spinlock_destroy(&reo_context->reo_algo_entry_lock);
7484
7485 status = mgmt_rx_reo_sim_deinit(reo_context);
7486 if (QDF_IS_STATUS_ERROR(status)) {
7487 mgmt_rx_reo_err("Failed to de initialize reo sim context");
7488 qdf_mem_free(reo_context);
7489 return QDF_STATUS_E_FAILURE;
7490 }
7491
7492 status = mgmt_rx_reo_egress_list_deinit(&reo_context->egress_list);
7493 if (QDF_IS_STATUS_ERROR(status)) {
7494 mgmt_rx_reo_err("Failed to de-initialize Rx reo egress list");
7495 qdf_mem_free(reo_context);
7496 return status;
7497 }
7498
7499 status = mgmt_rx_reo_ingress_list_deinit(&reo_context->ingress_list);
7500 if (QDF_IS_STATUS_ERROR(status)) {
7501 mgmt_rx_reo_err("Failed to de-initialize Rx reo ingress list");
7502 qdf_mem_free(reo_context);
7503 return status;
7504 }
7505
7506 mgmt_rx_reo_set_context(ml_grp_id, NULL);
7507 qdf_mem_free(reo_context);
7508
7509 return QDF_STATUS_SUCCESS;
7510 }
7511
7512 QDF_STATUS
mgmt_rx_reo_init_context(uint8_t ml_grp_id)7513 mgmt_rx_reo_init_context(uint8_t ml_grp_id)
7514 {
7515 QDF_STATUS status;
7516 QDF_STATUS temp;
7517 struct mgmt_rx_reo_context *reo_context;
7518
7519 reo_context = qdf_mem_malloc(sizeof(struct mgmt_rx_reo_context));
7520 if (!reo_context) {
7521 mgmt_rx_reo_err("Failed to allocate reo context");
7522 return QDF_STATUS_E_NULL_VALUE;
7523 }
7524 reo_context->mlo_grp_id = ml_grp_id;
7525
7526 mgmt_rx_reo_set_context(ml_grp_id, reo_context);
7527
7528 status = mgmt_rx_reo_ingress_list_init(&reo_context->ingress_list);
7529 if (QDF_IS_STATUS_ERROR(status)) {
7530 mgmt_rx_reo_err("Failed to initialize Rx reo ingress list");
7531 goto free_reo_context;
7532 }
7533
7534 status = mgmt_rx_reo_egress_list_init(&reo_context->egress_list);
7535 if (QDF_IS_STATUS_ERROR(status)) {
7536 mgmt_rx_reo_err("Failed to initialize Rx reo egress list");
7537 goto deinit_reo_ingress_list;
7538 }
7539
7540 status = mgmt_rx_reo_sim_init(reo_context);
7541 if (QDF_IS_STATUS_ERROR(status)) {
7542 mgmt_rx_reo_err("Failed to initialize reo simulation context");
7543 goto deinit_reo_egress_list;
7544 }
7545
7546 qdf_spinlock_create(&reo_context->reo_algo_entry_lock);
7547 qdf_spinlock_create(&reo_context->frame_release_lock);
7548 qdf_atomic_init(&reo_context->context_id);
7549
7550 return QDF_STATUS_SUCCESS;
7551
7552 deinit_reo_egress_list:
7553 temp = mgmt_rx_reo_egress_list_deinit(&reo_context->egress_list);
7554 if (QDF_IS_STATUS_ERROR(temp)) {
7555 mgmt_rx_reo_err("Failed to de-initialize Rx reo egress list");
7556 return temp;
7557 }
7558 deinit_reo_ingress_list:
7559 temp = mgmt_rx_reo_ingress_list_deinit(&reo_context->ingress_list);
7560 if (QDF_IS_STATUS_ERROR(temp)) {
7561 mgmt_rx_reo_err("Failed to de-initialize Rx reo ingress list");
7562 return temp;
7563 }
7564 free_reo_context:
7565 mgmt_rx_reo_set_context(ml_grp_id, NULL);
7566 qdf_mem_free(reo_context);
7567
7568 return status;
7569 }
7570
7571 /**
7572 * wlan_mgmt_rx_reo_initialize_snapshot_params() - Initialize a given snapshot
7573 * params object
7574 * @snapshot_params: Pointer to snapshot params object
7575 *
7576 * Return: void
7577 */
7578 static void
wlan_mgmt_rx_reo_initialize_snapshot_params(struct mgmt_rx_reo_snapshot_params * snapshot_params)7579 wlan_mgmt_rx_reo_initialize_snapshot_params(
7580 struct mgmt_rx_reo_snapshot_params *snapshot_params)
7581 {
7582 snapshot_params->valid = false;
7583 snapshot_params->mgmt_pkt_ctr = 0;
7584 snapshot_params->global_timestamp = 0;
7585 }
7586
7587 /**
7588 * mgmt_rx_reo_initialize_snapshot_address() - Initialize management Rx reorder
7589 * snapshot addresses for a given pdev
7590 * @pdev: pointer to pdev object
7591 *
7592 * Return: QDF_STATUS
7593 */
7594 static QDF_STATUS
mgmt_rx_reo_initialize_snapshot_address(struct wlan_objmgr_pdev * pdev)7595 mgmt_rx_reo_initialize_snapshot_address(struct wlan_objmgr_pdev *pdev)
7596 {
7597 enum mgmt_rx_reo_shared_snapshot_id snapshot_id;
7598 struct mgmt_rx_reo_pdev_info *mgmt_rx_reo_pdev_ctx;
7599 QDF_STATUS status;
7600
7601 mgmt_rx_reo_pdev_ctx = wlan_mgmt_rx_reo_get_priv_object(pdev);
7602 if (!mgmt_rx_reo_pdev_ctx) {
7603 mgmt_rx_reo_err("Mgmt Rx REO priv object is null");
7604 return QDF_STATUS_E_NULL_VALUE;
7605 }
7606
7607 snapshot_id = 0;
7608
7609 while (snapshot_id < MGMT_RX_REO_SHARED_SNAPSHOT_MAX) {
7610 struct mgmt_rx_reo_snapshot_info *snapshot_info;
7611
7612 snapshot_info =
7613 &mgmt_rx_reo_pdev_ctx->host_target_shared_snapshot_info
7614 [snapshot_id];
7615 status = wlan_mgmt_rx_reo_get_snapshot_info
7616 (pdev, snapshot_id, snapshot_info);
7617 if (QDF_IS_STATUS_ERROR(status)) {
7618 mgmt_rx_reo_err("Get snapshot info failed, id = %u",
7619 snapshot_id);
7620 return status;
7621 }
7622
7623 snapshot_id++;
7624 }
7625
7626 return QDF_STATUS_SUCCESS;
7627 }
7628
7629 /**
7630 * mgmt_rx_reo_initialize_snapshot_value() - Initialize management Rx reorder
7631 * snapshot values for a given pdev
7632 * @pdev: pointer to pdev object
7633 *
7634 * Return: QDF_STATUS
7635 */
7636 static QDF_STATUS
mgmt_rx_reo_initialize_snapshot_value(struct wlan_objmgr_pdev * pdev)7637 mgmt_rx_reo_initialize_snapshot_value(struct wlan_objmgr_pdev *pdev)
7638 {
7639 enum mgmt_rx_reo_shared_snapshot_id snapshot_id;
7640 struct mgmt_rx_reo_pdev_info *mgmt_rx_reo_pdev_ctx;
7641
7642 mgmt_rx_reo_pdev_ctx = wlan_mgmt_rx_reo_get_priv_object(pdev);
7643 if (!mgmt_rx_reo_pdev_ctx) {
7644 mgmt_rx_reo_err("Mgmt Rx REO priv object is null");
7645 return QDF_STATUS_E_NULL_VALUE;
7646 }
7647
7648 snapshot_id = 0;
7649 while (snapshot_id < MGMT_RX_REO_SHARED_SNAPSHOT_MAX) {
7650 wlan_mgmt_rx_reo_initialize_snapshot_params
7651 (&mgmt_rx_reo_pdev_ctx->last_valid_shared_snapshot
7652 [snapshot_id]);
7653 snapshot_id++;
7654 }
7655
7656 /* Initialize Host snapshot params */
7657 wlan_mgmt_rx_reo_initialize_snapshot_params
7658 (&mgmt_rx_reo_pdev_ctx->host_snapshot);
7659
7660 return QDF_STATUS_SUCCESS;
7661 }
7662
7663 /**
7664 * mgmt_rx_reo_set_initialization_complete() - Set initialization completion
7665 * for management Rx REO pdev component private object
7666 * @pdev: pointer to pdev object
7667 *
7668 * Return: QDF_STATUS
7669 */
7670 static QDF_STATUS
mgmt_rx_reo_set_initialization_complete(struct wlan_objmgr_pdev * pdev)7671 mgmt_rx_reo_set_initialization_complete(struct wlan_objmgr_pdev *pdev)
7672 {
7673 struct mgmt_rx_reo_pdev_info *mgmt_rx_reo_pdev_ctx;
7674
7675 mgmt_rx_reo_pdev_ctx = wlan_mgmt_rx_reo_get_priv_object(pdev);
7676 if (!mgmt_rx_reo_pdev_ctx) {
7677 mgmt_rx_reo_err("Mgmt Rx REO priv object is null");
7678 return QDF_STATUS_E_NULL_VALUE;
7679 }
7680
7681 mgmt_rx_reo_pdev_ctx->init_complete = true;
7682
7683 return QDF_STATUS_SUCCESS;
7684 }
7685
7686 /**
7687 * mgmt_rx_reo_clear_initialization_complete() - Clear initialization completion
7688 * for management Rx REO pdev component private object
7689 * @pdev: pointer to pdev object
7690 *
7691 * Return: QDF_STATUS
7692 */
7693 static QDF_STATUS
mgmt_rx_reo_clear_initialization_complete(struct wlan_objmgr_pdev * pdev)7694 mgmt_rx_reo_clear_initialization_complete(struct wlan_objmgr_pdev *pdev)
7695 {
7696 struct mgmt_rx_reo_pdev_info *mgmt_rx_reo_pdev_ctx;
7697
7698 mgmt_rx_reo_pdev_ctx = wlan_mgmt_rx_reo_get_priv_object(pdev);
7699 if (!mgmt_rx_reo_pdev_ctx) {
7700 mgmt_rx_reo_err("Mgmt Rx REO priv object is null");
7701 return QDF_STATUS_E_NULL_VALUE;
7702 }
7703
7704 mgmt_rx_reo_pdev_ctx->init_complete = false;
7705
7706 return QDF_STATUS_SUCCESS;
7707 }
7708
7709 /**
7710 * mgmt_rx_reo_initialize_snapshots() - Initialize management Rx reorder
7711 * snapshot related data structures for a given pdev
7712 * @pdev: pointer to pdev object
7713 *
7714 * Return: QDF_STATUS
7715 */
7716 static QDF_STATUS
mgmt_rx_reo_initialize_snapshots(struct wlan_objmgr_pdev * pdev)7717 mgmt_rx_reo_initialize_snapshots(struct wlan_objmgr_pdev *pdev)
7718 {
7719 QDF_STATUS status;
7720
7721 status = mgmt_rx_reo_initialize_snapshot_value(pdev);
7722 if (QDF_IS_STATUS_ERROR(status)) {
7723 mgmt_rx_reo_err("Failed to initialize snapshot value");
7724 return status;
7725 }
7726
7727 status = mgmt_rx_reo_initialize_snapshot_address(pdev);
7728 if (QDF_IS_STATUS_ERROR(status)) {
7729 mgmt_rx_reo_err("Failed to initialize snapshot address");
7730 return status;
7731 }
7732
7733 return QDF_STATUS_SUCCESS;
7734 }
7735
7736 /**
7737 * mgmt_rx_reo_clear_snapshots() - Clear management Rx reorder snapshot related
7738 * data structures for a given pdev
7739 * @pdev: pointer to pdev object
7740 *
7741 * Return: QDF_STATUS
7742 */
7743 static QDF_STATUS
mgmt_rx_reo_clear_snapshots(struct wlan_objmgr_pdev * pdev)7744 mgmt_rx_reo_clear_snapshots(struct wlan_objmgr_pdev *pdev)
7745 {
7746 QDF_STATUS status;
7747
7748 status = mgmt_rx_reo_initialize_snapshot_value(pdev);
7749 if (QDF_IS_STATUS_ERROR(status)) {
7750 mgmt_rx_reo_err("Failed to initialize snapshot value");
7751 return status;
7752 }
7753
7754 return QDF_STATUS_SUCCESS;
7755 }
7756
7757 QDF_STATUS
mgmt_rx_reo_pdev_attach(struct wlan_objmgr_pdev * pdev)7758 mgmt_rx_reo_pdev_attach(struct wlan_objmgr_pdev *pdev)
7759 {
7760 QDF_STATUS status;
7761
7762 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev))
7763 return QDF_STATUS_SUCCESS;
7764
7765 status = mgmt_rx_reo_initialize_snapshots(pdev);
7766 if (QDF_IS_STATUS_ERROR(status)) {
7767 mgmt_rx_reo_err("Failed to initialize mgmt Rx REO snapshots");
7768 return status;
7769 }
7770
7771 status = mgmt_rx_reo_set_initialization_complete(pdev);
7772 if (QDF_IS_STATUS_ERROR(status)) {
7773 mgmt_rx_reo_err("Failed to set initialization complete");
7774 return status;
7775 }
7776
7777 return QDF_STATUS_SUCCESS;
7778 }
7779
7780 QDF_STATUS
mgmt_rx_reo_psoc_attach(struct wlan_objmgr_psoc * psoc)7781 mgmt_rx_reo_psoc_attach(struct wlan_objmgr_psoc *psoc)
7782 {
7783 return QDF_STATUS_SUCCESS;
7784 }
7785
7786 QDF_STATUS
mgmt_rx_reo_pdev_detach(struct wlan_objmgr_pdev * pdev)7787 mgmt_rx_reo_pdev_detach(struct wlan_objmgr_pdev *pdev)
7788 {
7789 QDF_STATUS status;
7790
7791 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev))
7792 return QDF_STATUS_SUCCESS;
7793
7794 status = mgmt_rx_reo_clear_initialization_complete(pdev);
7795 if (QDF_IS_STATUS_ERROR(status)) {
7796 mgmt_rx_reo_err("Failed to clear initialization complete");
7797 return status;
7798 }
7799
7800 status = mgmt_rx_reo_clear_snapshots(pdev);
7801 if (QDF_IS_STATUS_ERROR(status)) {
7802 mgmt_rx_reo_err("Failed to clear mgmt Rx REO snapshots");
7803 return status;
7804 }
7805
7806 return QDF_STATUS_SUCCESS;
7807 }
7808
7809 QDF_STATUS
mgmt_rx_reo_psoc_detach(struct wlan_objmgr_psoc * psoc)7810 mgmt_rx_reo_psoc_detach(struct wlan_objmgr_psoc *psoc)
7811 {
7812 return QDF_STATUS_SUCCESS;
7813 }
7814
7815 QDF_STATUS
mgmt_rx_reo_pdev_obj_create_notification(struct wlan_objmgr_pdev * pdev,struct mgmt_txrx_priv_pdev_context * mgmt_txrx_pdev_ctx)7816 mgmt_rx_reo_pdev_obj_create_notification(
7817 struct wlan_objmgr_pdev *pdev,
7818 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx)
7819 {
7820 QDF_STATUS status;
7821 struct mgmt_rx_reo_pdev_info *mgmt_rx_reo_pdev_ctx = NULL;
7822
7823 if (!pdev) {
7824 mgmt_rx_reo_err("pdev is null");
7825 status = QDF_STATUS_E_NULL_VALUE;
7826 goto failure;
7827 }
7828
7829 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev)) {
7830 status = QDF_STATUS_SUCCESS;
7831 goto failure;
7832 }
7833
7834 status = mgmt_rx_reo_sim_pdev_object_create_notification(pdev);
7835 if (QDF_IS_STATUS_ERROR(status)) {
7836 mgmt_rx_reo_err("Failed to handle pdev create for reo sim");
7837 goto failure;
7838 }
7839
7840 mgmt_rx_reo_pdev_ctx = qdf_mem_malloc(sizeof(*mgmt_rx_reo_pdev_ctx));
7841 if (!mgmt_rx_reo_pdev_ctx) {
7842 mgmt_rx_reo_err("Allocation failure for REO pdev context");
7843 status = QDF_STATUS_E_NOMEM;
7844 goto failure;
7845 }
7846
7847 mgmt_txrx_pdev_ctx->mgmt_rx_reo_pdev_ctx = mgmt_rx_reo_pdev_ctx;
7848
7849 status = mgmt_rx_reo_debug_info_init(pdev);
7850 if (QDF_IS_STATUS_ERROR(status)) {
7851 mgmt_rx_reo_err("Failed to initialize debug info");
7852 status = QDF_STATUS_E_NOMEM;
7853 goto failure;
7854 }
7855
7856 return QDF_STATUS_SUCCESS;
7857
7858 failure:
7859 if (mgmt_rx_reo_pdev_ctx)
7860 qdf_mem_free(mgmt_rx_reo_pdev_ctx);
7861
7862 mgmt_txrx_pdev_ctx->mgmt_rx_reo_pdev_ctx = NULL;
7863
7864 return status;
7865 }
7866
7867 QDF_STATUS
mgmt_rx_reo_pdev_obj_destroy_notification(struct wlan_objmgr_pdev * pdev,struct mgmt_txrx_priv_pdev_context * mgmt_txrx_pdev_ctx)7868 mgmt_rx_reo_pdev_obj_destroy_notification(
7869 struct wlan_objmgr_pdev *pdev,
7870 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx)
7871 {
7872 QDF_STATUS status;
7873
7874 if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev))
7875 return QDF_STATUS_SUCCESS;
7876
7877 status = mgmt_rx_reo_debug_info_deinit(pdev);
7878 if (QDF_IS_STATUS_ERROR(status)) {
7879 mgmt_rx_reo_err("Failed to de-initialize debug info");
7880 return status;
7881 }
7882
7883 qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_rx_reo_pdev_ctx);
7884 mgmt_txrx_pdev_ctx->mgmt_rx_reo_pdev_ctx = NULL;
7885
7886 status = mgmt_rx_reo_sim_pdev_object_destroy_notification(pdev);
7887 if (QDF_IS_STATUS_ERROR(status)) {
7888 mgmt_rx_reo_err("Failed to handle pdev create for reo sim");
7889 return status;
7890 }
7891
7892 return QDF_STATUS_SUCCESS;
7893 }
7894
7895 QDF_STATUS
mgmt_rx_reo_psoc_obj_create_notification(struct wlan_objmgr_psoc * psoc)7896 mgmt_rx_reo_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc)
7897 {
7898 return QDF_STATUS_SUCCESS;
7899 }
7900
7901 QDF_STATUS
mgmt_rx_reo_psoc_obj_destroy_notification(struct wlan_objmgr_psoc * psoc)7902 mgmt_rx_reo_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc)
7903 {
7904 return QDF_STATUS_SUCCESS;
7905 }
7906
7907 bool
mgmt_rx_reo_is_simulation_in_progress(uint8_t ml_grp_id)7908 mgmt_rx_reo_is_simulation_in_progress(uint8_t ml_grp_id)
7909 {
7910 struct mgmt_rx_reo_context *reo_context;
7911
7912 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
7913 if (!reo_context) {
7914 mgmt_rx_reo_err("reo context is null");
7915 return false;
7916 }
7917
7918 return reo_context->simulation_in_progress;
7919 }
7920
7921 #ifdef WLAN_MGMT_RX_REO_DEBUG_SUPPORT
7922 QDF_STATUS
mgmt_rx_reo_print_ingress_frame_stats(uint8_t ml_grp_id)7923 mgmt_rx_reo_print_ingress_frame_stats(uint8_t ml_grp_id)
7924 {
7925 struct mgmt_rx_reo_context *reo_context;
7926 QDF_STATUS status;
7927
7928 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
7929 if (!reo_context) {
7930 mgmt_rx_reo_err("reo context is null");
7931 return QDF_STATUS_E_NULL_VALUE;
7932 }
7933
7934 status = mgmt_rx_reo_debug_print_ingress_frame_stats(reo_context);
7935 if (QDF_IS_STATUS_ERROR(status)) {
7936 mgmt_rx_reo_err("Failed to print ingress frame stats");
7937 return status;
7938 }
7939
7940 return QDF_STATUS_SUCCESS;
7941 }
7942
7943 QDF_STATUS
mgmt_rx_reo_print_ingress_frame_info(uint8_t ml_grp_id,uint16_t num_frames)7944 mgmt_rx_reo_print_ingress_frame_info(uint8_t ml_grp_id, uint16_t num_frames)
7945 {
7946 struct mgmt_rx_reo_context *reo_context;
7947 QDF_STATUS status;
7948
7949 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
7950 if (!reo_context) {
7951 mgmt_rx_reo_err("reo context is null");
7952 return QDF_STATUS_E_NULL_VALUE;
7953 }
7954
7955 status = mgmt_rx_reo_debug_print_ingress_frame_info(reo_context,
7956 num_frames);
7957 if (QDF_IS_STATUS_ERROR(status)) {
7958 mgmt_rx_reo_err("Failed to print ingress frame info");
7959 return status;
7960 }
7961
7962 return QDF_STATUS_SUCCESS;
7963 }
7964
7965 QDF_STATUS
mgmt_rx_reo_print_egress_frame_stats(uint8_t ml_grp_id)7966 mgmt_rx_reo_print_egress_frame_stats(uint8_t ml_grp_id)
7967 {
7968 struct mgmt_rx_reo_context *reo_context;
7969 QDF_STATUS status;
7970
7971 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
7972 if (!reo_context) {
7973 mgmt_rx_reo_err("reo context is null");
7974 return QDF_STATUS_E_NULL_VALUE;
7975 }
7976
7977 status = mgmt_rx_reo_debug_print_egress_frame_stats(reo_context);
7978 if (QDF_IS_STATUS_ERROR(status)) {
7979 mgmt_rx_reo_err("Failed to print egress frame stats");
7980 return status;
7981 }
7982
7983 return QDF_STATUS_SUCCESS;
7984 }
7985
7986 QDF_STATUS
mgmt_rx_reo_print_egress_frame_info(uint8_t ml_grp_id,uint16_t num_frames)7987 mgmt_rx_reo_print_egress_frame_info(uint8_t ml_grp_id, uint16_t num_frames)
7988 {
7989 struct mgmt_rx_reo_context *reo_context;
7990 QDF_STATUS status;
7991
7992 reo_context = mgmt_rx_reo_get_context(ml_grp_id);
7993 if (!reo_context) {
7994 mgmt_rx_reo_err("reo context is null");
7995 return QDF_STATUS_E_NULL_VALUE;
7996 }
7997
7998 status = mgmt_rx_reo_debug_print_egress_frame_info(reo_context,
7999 num_frames);
8000 if (QDF_IS_STATUS_ERROR(status)) {
8001 mgmt_rx_reo_err("Failed to print egress frame info");
8002 return status;
8003 }
8004
8005 return QDF_STATUS_SUCCESS;
8006 }
8007 #else
8008 QDF_STATUS
mgmt_rx_reo_print_ingress_frame_stats(uint8_t ml_grp_id)8009 mgmt_rx_reo_print_ingress_frame_stats(uint8_t ml_grp_id)
8010 {
8011 return QDF_STATUS_SUCCESS;
8012 }
8013
8014 QDF_STATUS
mgmt_rx_reo_print_ingress_frame_info(uint8_t ml_grp_id,uint16_t num_frames)8015 mgmt_rx_reo_print_ingress_frame_info(uint8_t ml_grp_id, uint16_t num_frames)
8016 {
8017 return QDF_STATUS_SUCCESS;
8018 }
8019
8020 QDF_STATUS
mgmt_rx_reo_print_egress_frame_stats(uint8_t ml_grp_id)8021 mgmt_rx_reo_print_egress_frame_stats(uint8_t ml_grp_id)
8022 {
8023 return QDF_STATUS_SUCCESS;
8024 }
8025
8026 QDF_STATUS
mgmt_rx_reo_print_egress_frame_info(uint8_t ml_grp_id,uint16_t num_frames)8027 mgmt_rx_reo_print_egress_frame_info(uint8_t ml_grp_id, uint16_t num_frames)
8028 {
8029 return QDF_STATUS_SUCCESS;
8030 }
8031 #endif /* WLAN_MGMT_RX_REO_DEBUG_SUPPORT */
8032