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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 5453 mgmt_rx_reo_sim_deinit(struct mgmt_rx_reo_context *reo_context) 5454 { 5455 return QDF_STATUS_SUCCESS; 5456 } 5457 5458 QDF_STATUS 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 7348 mgmt_rx_reo_debug_info_init(struct wlan_objmgr_pdev *pdev) 7349 { 7350 return QDF_STATUS_SUCCESS; 7351 } 7352 7353 static QDF_STATUS 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 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 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 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 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 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 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 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 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 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 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 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 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 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 7781 mgmt_rx_reo_psoc_attach(struct wlan_objmgr_psoc *psoc) 7782 { 7783 return QDF_STATUS_SUCCESS; 7784 } 7785 7786 QDF_STATUS 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 7810 mgmt_rx_reo_psoc_detach(struct wlan_objmgr_psoc *psoc) 7811 { 7812 return QDF_STATUS_SUCCESS; 7813 } 7814 7815 QDF_STATUS 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 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 7896 mgmt_rx_reo_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc) 7897 { 7898 return QDF_STATUS_SUCCESS; 7899 } 7900 7901 QDF_STATUS 7902 mgmt_rx_reo_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc) 7903 { 7904 return QDF_STATUS_SUCCESS; 7905 } 7906 7907 bool 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 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 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 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 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 8009 mgmt_rx_reo_print_ingress_frame_stats(uint8_t ml_grp_id) 8010 { 8011 return QDF_STATUS_SUCCESS; 8012 } 8013 8014 QDF_STATUS 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 8021 mgmt_rx_reo_print_egress_frame_stats(uint8_t ml_grp_id) 8022 { 8023 return QDF_STATUS_SUCCESS; 8024 } 8025 8026 QDF_STATUS 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