1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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: mlo_global_h_shmem_arena.c 20 * This file contains definition of functions that parse the MLO global 21 * shared memory arena. 22 */ 23 24 #include<mlo_global_h_shmem_arena.h> 25 #include<wlan_mlo_mgr_public_structs.h> 26 static struct wlan_host_mlo_glb_h_shmem_arena_ctx 27 g_shmem_arena_ctx[WLAN_MAX_MLO_GROUPS]; 28 29 #define get_shmem_arena_ctx(__grp_id) (&g_shmem_arena_ctx[__grp_id]) 30 31 /** 32 * is_field_present_in_tlv() - Check whether a given field is present 33 * in a given TLV 34 * @ptlv: Pointer to start of the TLV 35 * @field_name: name of the field in the TLV structure 36 * @tlv_len: Length of the TLV 37 * 38 * Return: true if the field is present within the TLV, 39 * else false 40 */ 41 #define is_field_present_in_tlv(ptlv, field_name, tlv_len) \ 42 (qdf_offsetof(typeof(*(ptlv)), field_name) < (tlv_len) ? \ 43 true : false) 44 45 /** 46 * get_field_value_in_tlv() - Get the value of a given field in a given TLV 47 * @ptlv: Pointer to start of the TLV 48 * @field_name: name of the field in the TLV structure 49 * @tlv_len: Length of the TLV 50 * 51 * Return: Value of the given field if the offset of the field with in the TLV 52 * structure is less than the TLV length, else 0. 53 */ 54 #define get_field_value_in_tlv(ptlv, field_name, tlv_len) \ 55 (qdf_offsetof(typeof(*(ptlv)), field_name) < (tlv_len) ? \ 56 (ptlv)->field_name : 0) 57 58 /** 59 * get_field_pointer_in_tlv() - Get the address of a given field in a given TLV 60 * @ptlv: Pointer to start of the TLV 61 * @field_name: name of the field in the TLV structure 62 * @tlv_len: Length of the TLV 63 * 64 * Return: Address of the given field if the offset of the field with in the 65 * TLV structure is less than the TLV length, else NULL. 66 */ 67 #define get_field_pointer_in_tlv(ptlv, field_name, tlv_len) \ 68 (qdf_offsetof(typeof(*(ptlv)), field_name) < (tlv_len) ? \ 69 &(ptlv)->field_name : NULL) 70 71 /** 72 * process_tlv_header() - Process a given TLV header 73 * @data: Pointer to start of the TLV 74 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 75 * @expected_tag: Expected TLV tag 76 * @tlv_len: Address of TLV length variable to be populated. This API populates 77 * the entire length(payload + header) of the TLV into @tlv_len 78 * @tlv_tag: Address of TLV Tag variable to be populated. 79 * 80 * Return: 0 on success, -1 on failure 81 */ 82 static int 83 process_tlv_header(const uint8_t *data, size_t remaining_len, 84 uint32_t expected_tag, uint32_t *tlv_len, 85 uint32_t *tlv_tag) 86 { 87 if (remaining_len < MLO_SHMEM_TLV_HDR_SIZE) { 88 target_if_err("Not enough space(%zu) to read TLV header(%u)", 89 remaining_len, (uint32_t)MLO_SHMEM_TLV_HDR_SIZE); 90 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 91 } 92 93 *tlv_len = MLO_SHMEMTLV_GET_TLVLEN(MLO_SHMEMTLV_GET_HDR(data)); 94 *tlv_len += MLO_SHMEM_TLV_HDR_SIZE; 95 if (remaining_len < *tlv_len) { 96 target_if_err("Not enough space(%zu) to read TLV payload(%u)", 97 remaining_len, *tlv_len); 98 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 99 } 100 101 *tlv_tag = MLO_SHMEMTLV_GET_TLVTAG(MLO_SHMEMTLV_GET_HDR(data)); 102 if (*tlv_tag != expected_tag) { 103 target_if_err("Unexpected TLV tag: %u is seen. Expected: %u", 104 *tlv_tag, 105 expected_tag); 106 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 107 } 108 109 return 0; 110 } 111 112 #define validate_parsed_bytes_advance_data_pointer(parsed_bytes, data, \ 113 remaining_len) \ 114 do { \ 115 if ((parsed_bytes) < 0) { \ 116 target_if_err("TLV extraction failed"); \ 117 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); \ 118 } \ 119 (data) += (parsed_bytes); \ 120 (remaining_len) -= (parsed_bytes); \ 121 } while (0) 122 123 /** 124 * extract_mgmt_rx_reo_snapshot_tlv() - extract MGMT_RX_REO_SNAPSHOT TLV 125 * @data: Pointer to start of the TLV 126 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 127 * @address_ptr: Pointer to the snapshot address. This API will populate the 128 * snapshot address into the variable pointed by @address_ptr 129 * 130 * Return: On success, the number of bytes parsed. On failure, -1. 131 */ 132 static int 133 extract_mgmt_rx_reo_snapshot_tlv(uint8_t *data, size_t remaining_len, 134 void **address_ptr) 135 { 136 mgmt_rx_reo_snapshot *ptlv; 137 uint32_t tlv_len, tlv_tag; 138 139 qdf_assert_always(data); 140 qdf_assert_always(address_ptr); 141 142 /* process MLO_SHMEM_TLV_STRUCT_MGMT_RX_REO_SNAPSHOT TLV */ 143 if (process_tlv_header(data, remaining_len, 144 MLO_SHMEM_TLV_STRUCT_MGMT_RX_REO_SNAPSHOT, 145 &tlv_len, &tlv_tag) != 0) { 146 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 147 } 148 149 ptlv = (mgmt_rx_reo_snapshot *)data; 150 *address_ptr = get_field_pointer_in_tlv(ptlv, mgmt_rx_reo_snapshot_low, 151 tlv_len); 152 153 return tlv_len; 154 } 155 156 /** 157 * extract_mlo_glb_rx_reo_per_link_info_tlv() - extract 158 * RX_REO_PER_LINK_SNAPSHOT_INFO TLV 159 * @data: Pointer to start of the TLV 160 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 161 * @link_info: Pointer to MGMT Rx REO per link info. Extracted information 162 * will be populated in this data structure. 163 * 164 * Return: On success, the number of bytes parsed. On failure, -1. 165 */ 166 static int 167 extract_mlo_glb_rx_reo_per_link_info_tlv( 168 uint8_t *data, size_t remaining_len, uint8_t link_id, 169 struct wlan_host_mlo_glb_rx_reo_per_link_info *link_info) 170 { 171 mlo_glb_rx_reo_per_link_snapshot_info *ptlv; 172 uint32_t tlv_len, tlv_tag; 173 int len; 174 uint8_t *fw_consumed; 175 int parsed_bytes; 176 177 qdf_assert_always(data); 178 qdf_assert_always(link_info); 179 180 /* process MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_PER_LINK_SNAPSHOT_INFO TLV */ 181 if (process_tlv_header(data, remaining_len, 182 MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_PER_LINK_SNAPSHOT_INFO, 183 &tlv_len, &tlv_tag) != 0) { 184 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 185 } 186 187 ptlv = (mlo_glb_rx_reo_per_link_snapshot_info *)data; 188 189 link_info->link_id = link_id; 190 191 /** 192 * Get the pointer to the fw_consumed snapshot with in the TLV. 193 * Note that snapshots are nested TLVs within link_sanpshot_info TLV. 194 */ 195 data += qdf_offsetof(mlo_glb_rx_reo_per_link_snapshot_info, 196 fw_consumed); 197 fw_consumed = (uint8_t *)get_field_pointer_in_tlv(ptlv, fw_consumed, 198 tlv_len); 199 remaining_len -= qdf_offsetof(mlo_glb_rx_reo_per_link_snapshot_info, 200 fw_consumed); 201 parsed_bytes = qdf_offsetof(mlo_glb_rx_reo_per_link_snapshot_info, 202 fw_consumed); 203 204 /* extract fw_consumed snapshot */ 205 len = extract_mgmt_rx_reo_snapshot_tlv(data, remaining_len, 206 &link_info->fw_consumed); 207 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 208 parsed_bytes += len; 209 210 /* extract fw_forwarded snapshot */ 211 len = extract_mgmt_rx_reo_snapshot_tlv(data, remaining_len, 212 &link_info->fw_forwarded); 213 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 214 parsed_bytes += len; 215 216 /* extract hw_forwarded snapshot */ 217 len = extract_mgmt_rx_reo_snapshot_tlv(data, remaining_len, 218 &link_info->hw_forwarded); 219 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 220 parsed_bytes += len; 221 222 /** 223 * Return the length of link_sanpshot_info TLV itself as the snapshots 224 * are nested inside link_sanpshot_info TLV and hence no need to add 225 * their lengths separately. 226 */ 227 return tlv_len; 228 } 229 230 /** 231 * get_num_links_from_valid_link_bitmap() - Get the number of valid links 232 * @valid_link_bmap: Link bit map where the valid links are set to 1 233 * 234 * Return: Number of valid links 235 */ 236 static uint8_t 237 get_num_links_from_valid_link_bitmap(uint16_t valid_link_bmap) 238 { 239 uint8_t num_links = 0; 240 241 /* Find the number of set bits */ 242 while (valid_link_bmap) { 243 num_links++; 244 valid_link_bmap &= (valid_link_bmap - 1); 245 } 246 247 return num_links; 248 } 249 250 /** 251 * extract_mlo_glb_rx_reo_snapshot_info_tlv() - extract 252 * MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO TLV 253 * @data: Pointer to start of the TLV 254 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 255 * @snapshot_info: Pointer to MGMT Rx REO snapshot info. Extracted information 256 * will be populated in this data structure. 257 * 258 * Return: On success, the number of bytes parsed. On failure, -1. 259 */ 260 static int 261 extract_mlo_glb_rx_reo_snapshot_info_tlv( 262 uint8_t *data, size_t remaining_len, 263 struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info) 264 { 265 mlo_glb_rx_reo_snapshot_info *ptlv; 266 uint32_t tlv_len, tlv_tag; 267 uint32_t link_info; 268 uint16_t valid_link_bmap; 269 270 qdf_assert_always(data); 271 qdf_assert_always(snapshot_info); 272 273 /* process MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO TLV */ 274 if (process_tlv_header(data, remaining_len, 275 MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO, 276 &tlv_len, &tlv_tag) != 0) { 277 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 278 } 279 280 ptlv = (mlo_glb_rx_reo_snapshot_info *)data; 281 link_info = get_field_value_in_tlv(ptlv, link_info, tlv_len); 282 valid_link_bmap = 283 MLO_SHMEM_GLB_LINK_INFO_PARAM_VALID_LINK_BMAP_GET(link_info); 284 285 snapshot_info->valid_link_bmap = valid_link_bmap; 286 287 if (is_field_present_in_tlv(ptlv, snapshot_ver_info, tlv_len)) { 288 uint32_t snapshot_ver_info; 289 290 snapshot_ver_info = get_field_value_in_tlv 291 (ptlv, snapshot_ver_info, tlv_len); 292 snapshot_info->hw_forwarded_snapshot_ver = 293 MLO_SHMEM_GLB_RX_REO_SNAPSHOT_PARAM_HW_FWD_SNAPSHOT_VER_GET(snapshot_ver_info); 294 snapshot_info->fw_forwarded_snapshot_ver = 295 MLO_SHMEM_GLB_RX_REO_SNAPSHOT_PARAM_FW_FWD_SNAPSHOT_VER_GET(snapshot_ver_info); 296 snapshot_info->fw_consumed_snapshot_ver = 297 MLO_SHMEM_GLB_RX_REO_SNAPSHOT_PARAM_FW_CONSUMED_SNAPSHOT_VER_GET(snapshot_ver_info); 298 } 299 300 snapshot_info->num_links = 301 get_num_links_from_valid_link_bitmap(valid_link_bmap); 302 snapshot_info->link_info = qdf_mem_malloc( 303 sizeof(*snapshot_info->link_info) * 304 snapshot_info->num_links); 305 if (!snapshot_info->link_info) { 306 target_if_err("Couldn't allocate memory for rx_reo_per_link_info"); 307 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 308 } 309 310 return tlv_len; 311 } 312 313 /** 314 * extract_mlo_glb_link_info_tlv() - extract lobal link info from shmem 315 * @data: Pointer to the first TLV in the arena 316 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 317 * @link_info: Pointer to which link info needs to be copied 318 * 319 * Return: On success, the number of bytes parsed. On failure, -1. 320 */ 321 static int 322 extract_mlo_glb_link_info_tlv(uint8_t *data, 323 size_t remaining_len, 324 uint32_t *link_info) 325 { 326 mlo_glb_link_info *ptlv; 327 uint32_t tlv_len, tlv_tag; 328 329 qdf_assert_always(data); 330 qdf_assert_always(link_info); 331 332 if (process_tlv_header(data, remaining_len, 333 MLO_SHMEM_TLV_STRUCT_MLO_GLB_LINK_INFO, 334 &tlv_len, &tlv_tag) != 0) { 335 return -EPERM; 336 } 337 338 ptlv = (mlo_glb_link_info *)data; 339 340 *link_info = get_field_value_in_tlv(ptlv, link_info, tlv_len); 341 342 return tlv_len; 343 } 344 345 /** 346 * process_mlo_glb_per_link_status_tlv() - process per link info 347 * @data: Pointer to the first TLV in the arena 348 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 349 * 350 * Return: On success, the number of bytes parsed. On failure, -1. 351 */ 352 static int 353 process_mlo_glb_per_link_status_tlv(uint8_t *data, size_t remaining_len) 354 { 355 uint32_t tlv_len, tlv_tag; 356 357 qdf_assert_always(data); 358 359 if (process_tlv_header(data, remaining_len, 360 MLO_SHMEM_TLV_STRUCT_MLO_GLB_LINK, 361 &tlv_len, &tlv_tag) != 0) { 362 return -EPERM; 363 } 364 365 return tlv_len; 366 } 367 368 /** 369 * parse_global_link_info() - parse lobal link info 370 * @data: Pointer to the first TLV in the arena 371 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 372 * 373 * Return: On success, the number of bytes parsed. On failure, -1. 374 */ 375 static int 376 parse_global_link_info(uint8_t *data, size_t remaining_len) 377 { 378 int parsed_bytes, len; 379 uint8_t link; 380 uint32_t link_info; 381 uint8_t num_links; 382 383 qdf_assert_always(data); 384 385 /* Extract MLO_SHMEM_TLV_STRUCT_MLO_GLB_LINK_INFO_TLV */ 386 len = extract_mlo_glb_link_info_tlv(data, remaining_len, &link_info); 387 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 388 parsed_bytes = len; 389 390 num_links = MLO_SHMEM_GLB_LINK_INFO_PARAM_NO_OF_LINKS_GET(link_info); 391 392 for (link = 0; link < num_links; link++) { 393 len = process_mlo_glb_per_link_status_tlv(data, remaining_len); 394 validate_parsed_bytes_advance_data_pointer(len, data, 395 remaining_len); 396 parsed_bytes += len; 397 } 398 399 return parsed_bytes; 400 } 401 402 /** 403 * free_mlo_glb_rx_reo_per_link_info() - Free Rx REO per-link info 404 * @snapshot_info: Pointer to MGMT Rx REO snapshot info 405 * 406 * Return: None 407 */ 408 static void free_mlo_glb_rx_reo_per_link_info( 409 struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info) 410 { 411 if (snapshot_info && snapshot_info->link_info) { 412 qdf_mem_free(snapshot_info->link_info); 413 snapshot_info->link_info = NULL; 414 } 415 } 416 417 /** 418 * get_next_valid_link_id() - Get next valid link ID 419 * @valid_link_bmap: Link bit map where the valid links are set to 1 420 * @prev_link_id: Previous link ID 421 * 422 * Return: Next valid link ID if there are valid links after @prev_link_id, 423 * else -1 424 */ 425 static int 426 get_next_valid_link_id(uint16_t valid_link_bmap, int prev_link_id) 427 { 428 int cur_link_id; 429 uint16_t mask; 430 uint8_t maxbits = sizeof(valid_link_bmap) * QDF_CHAR_BIT; 431 432 cur_link_id = prev_link_id + 1; 433 mask = 1 << cur_link_id; 434 435 while (!(valid_link_bmap & mask)) { 436 cur_link_id++; 437 if (cur_link_id == maxbits) 438 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 439 mask = mask << 1; 440 } 441 442 return cur_link_id; 443 } 444 445 /** 446 * extract_mlo_glb_rx_reo_snapshot_info() - extract MGMT Rx REO snapshot info 447 * @data: Pointer to start of MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO 448 * TLV 449 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 450 * @snapshot_info: Pointer to MGMT Rx REO snapshot info. Extracted information 451 * will be populated in this data structure. 452 * 453 * Return: On success, the number of bytes parsed. On failure, -1. 454 */ 455 static int 456 extract_mlo_glb_rx_reo_snapshot_info( 457 uint8_t *data, size_t remaining_len, 458 struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info) 459 { 460 int parsed_bytes, len; 461 uint8_t link; 462 int cur_link_id, prev_link_id = -1; 463 uint16_t valid_link_bmap; 464 465 qdf_assert_always(data); 466 qdf_assert_always(snapshot_info); 467 468 /* Extract MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO TLV */ 469 len = extract_mlo_glb_rx_reo_snapshot_info_tlv(data, remaining_len, 470 snapshot_info); 471 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 472 parsed_bytes = len; 473 474 valid_link_bmap = snapshot_info->valid_link_bmap; 475 /* Foreach valid link */ 476 for (link = 0; link < snapshot_info->num_links; ++link) { 477 cur_link_id = get_next_valid_link_id(valid_link_bmap, 478 prev_link_id); 479 480 qdf_assert_always(cur_link_id >= 0); 481 482 /* Extract per_link_info */ 483 len = extract_mlo_glb_rx_reo_per_link_info_tlv( 484 data, remaining_len, cur_link_id, 485 &snapshot_info->link_info[link]); 486 validate_parsed_bytes_advance_data_pointer(len, data, 487 remaining_len); 488 parsed_bytes += len; 489 prev_link_id = cur_link_id; 490 } 491 492 return parsed_bytes; 493 } 494 495 /** 496 * mlo_glb_h_shmem_arena_get_no_of_chips_from_crash_info() - get the number of 497 * chips from crash info 498 * @grp_id: Id of the required MLO Group 499 * 500 * Return: number of chips participating in MLO from crash info shared by target 501 * in case of success, else returns 0 502 */ 503 uint8_t mlo_glb_h_shmem_arena_get_no_of_chips_from_crash_info(uint8_t grp_id) 504 { 505 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 506 507 if (grp_id > WLAN_MAX_MLO_GROUPS) 508 return 0; 509 510 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 511 512 if (!shmem_arena_ctx) { 513 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 514 return 0; 515 } 516 517 return shmem_arena_ctx->chip_crash_info.no_of_chips; 518 } 519 520 /** 521 * mlo_glb_h_shmem_arena_get_crash_reason_address() - get the address of crash 522 * reason associated with chip_id 523 * @grp_id: Id of the required MLO Group 524 * @chip_id: MLO Chip Id 525 * 526 * Return: Address of crash_reason field from global shmem arena in case of 527 * success, else returns NULL 528 */ 529 void *mlo_glb_h_shmem_arena_get_crash_reason_address(uint8_t grp_id, 530 uint8_t chip_id) 531 { 532 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 533 struct wlan_host_mlo_glb_chip_crash_info *crash_info; 534 struct wlan_host_mlo_glb_per_chip_crash_info *per_chip_crash_info; 535 uint8_t chip; 536 537 if (grp_id > WLAN_MAX_MLO_GROUPS) 538 return NULL; 539 540 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 541 if (!shmem_arena_ctx) { 542 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 543 return NULL; 544 } 545 546 crash_info = &shmem_arena_ctx->chip_crash_info; 547 548 for (chip = 0; chip < crash_info->no_of_chips; chip++) { 549 per_chip_crash_info = &crash_info->per_chip_crash_info[chip]; 550 551 if (chip_id == per_chip_crash_info->chip_id) 552 break; 553 } 554 555 if (chip == crash_info->no_of_chips) { 556 target_if_err("No crash info corresponding to chip %u", 557 chip_id); 558 return NULL; 559 } 560 561 return per_chip_crash_info->crash_reason; 562 } 563 564 /** 565 * free_mlo_glb_per_chip_crash_info() - free per chip crash info 566 * @crash_info: Pointer to crash info 567 * 568 * Return: None 569 */ 570 static void free_mlo_glb_per_chip_crash_info( 571 struct wlan_host_mlo_glb_chip_crash_info *crash_info) 572 { 573 if (crash_info) { 574 qdf_mem_free(crash_info->per_chip_crash_info); 575 crash_info->per_chip_crash_info = NULL; 576 } 577 } 578 579 /** 580 * extract_mlo_glb_per_chip_crash_info_tlv() - extract PER_CHIP_CRASH_INFO TLV 581 * @data: Pointer to start of the TLV 582 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 583 * @chip_id: Chip id to which the crash info tlv being extracted. 584 * @chip_crash_info: Pointer to the per chip crash info. This API will populate 585 * the crash_reason address & chip_id into chip_crash_info 586 */ 587 static int extract_mlo_glb_per_chip_crash_info_tlv( 588 uint8_t *data, size_t remaining_len, uint8_t chip_id, 589 struct wlan_host_mlo_glb_per_chip_crash_info *chip_crash_info) 590 { 591 mlo_glb_per_chip_crash_info *ptlv; 592 uint32_t tlv_len, tlv_tag; 593 uint8_t *crash_reason; 594 595 qdf_assert_always(data); 596 qdf_assert_always(chip_crash_info); 597 598 /* process MLO_SHMEM_TLV_STRUCT_MLO_GLB_PER_CHIP_CRASH_INFO TLV */ 599 if (process_tlv_header(data, remaining_len, 600 MLO_SHMEM_TLV_STRUCT_MLO_GLB_PER_CHIP_CRASH_INFO, 601 &tlv_len, &tlv_tag) != 0) { 602 return -EPERM; 603 } 604 605 ptlv = (mlo_glb_per_chip_crash_info *)data; 606 607 chip_crash_info->chip_id = chip_id; 608 crash_reason = (uint8_t *)get_field_pointer_in_tlv( 609 ptlv, crash_reason, tlv_len); 610 chip_crash_info->crash_reason = (void *)crash_reason; 611 return tlv_len; 612 } 613 614 /** 615 * extract_mlo_glb_chip_crash_info_tlv() - extract CHIP_CRASH_INFO TLV 616 * @data: Pointer to start of the TLV 617 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 618 * @crash_info: Pointer to the crash_info structure to which crash info fields 619 * are populated. 620 * 621 * Return: On success, the number of bytes parsed. On failure, -1. 622 */ 623 static int extract_mlo_glb_chip_crash_info_tlv( 624 uint8_t *data, size_t remaining_len, 625 struct wlan_host_mlo_glb_chip_crash_info *crash_info) 626 { 627 mlo_glb_chip_crash_info *ptlv; 628 uint32_t tlv_len, tlv_tag; 629 uint32_t chip_info; 630 uint8_t chip_map; 631 632 qdf_assert_always(data); 633 qdf_assert_always(crash_info); 634 635 if (process_tlv_header(data, remaining_len, 636 MLO_SHMEM_TLV_STRUCT_MLO_GLB_CHIP_CRASH_INFO, 637 &tlv_len, &tlv_tag) != 0) { 638 return -EPERM; 639 } 640 641 ptlv = (mlo_glb_chip_crash_info *)data; 642 chip_info = get_field_value_in_tlv(ptlv, chip_info, tlv_len); 643 crash_info->no_of_chips = 644 MLO_SHMEM_CHIP_CRASH_INFO_PARAM_NO_OF_CHIPS_GET(chip_info); 645 chip_map = 646 MLO_SHMEM_CHIP_CRASH_INFO_PARAM_VALID_CHIP_BMAP_GET(chip_info); 647 qdf_mem_copy(crash_info->valid_chip_bmap, 648 &chip_map, 649 qdf_min(sizeof(crash_info->valid_chip_bmap), 650 sizeof(chip_map))); 651 652 crash_info->per_chip_crash_info = 653 qdf_mem_malloc(sizeof(*crash_info->per_chip_crash_info) * 654 crash_info->no_of_chips); 655 656 if (!crash_info->per_chip_crash_info) { 657 target_if_err("Couldn't allocate memory for crash info"); 658 return -EPERM; 659 } 660 661 return tlv_len; 662 } 663 664 /** 665 * extract_mlo_glb_chip_crash_info() - extract the crash information from global 666 * shmem arena 667 * @data: Pointer to start of the TLV 668 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 669 * @crash_info: Pointer to the crash_info structure to which crash info fields 670 * are populated. 671 * 672 * Return: On success, the number of bytes parsed. On failure, -1. 673 */ 674 static int extract_mlo_glb_chip_crash_info( 675 uint8_t *data, size_t remaining_len, 676 struct wlan_host_mlo_glb_chip_crash_info *crash_info) 677 { 678 int parsed_bytes, len; 679 int cur_chip_id; 680 qdf_bitmap(valid_chip_bmap, QDF_CHAR_BIT); 681 uint8_t chip; 682 683 qdf_assert_always(data); 684 qdf_assert_always(crash_info); 685 686 /* Extract MLO_SHMEM_TLV_STRUCT_MLO_GLB_CHIP_CRASH_INFO_TLV */ 687 len = extract_mlo_glb_chip_crash_info_tlv( 688 data, remaining_len, crash_info); 689 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 690 691 parsed_bytes = len; 692 qdf_mem_copy(valid_chip_bmap, 693 crash_info->valid_chip_bmap, 694 qdf_min(sizeof(valid_chip_bmap), 695 sizeof(crash_info->valid_chip_bmap))); 696 /* Foreach valid chip_id */ 697 for (chip = 0; chip < crash_info->no_of_chips; chip++) { 698 cur_chip_id = qdf_find_first_bit(valid_chip_bmap, QDF_CHAR_BIT); 699 qdf_clear_bit(cur_chip_id, valid_chip_bmap); 700 qdf_assert_always(cur_chip_id >= 0); 701 /* Extract per_chip_crash_info */ 702 len = extract_mlo_glb_per_chip_crash_info_tlv( 703 data, remaining_len, cur_chip_id, 704 &crash_info->per_chip_crash_info[chip]); 705 validate_parsed_bytes_advance_data_pointer( 706 len, data, remaining_len); 707 parsed_bytes += len; 708 } 709 return parsed_bytes; 710 } 711 712 /** 713 * extract_mlo_glb_h_shmem_tlv() - extract MLO_SHMEM_TLV_STRUCT_MLO_GLB_H_SHMEM 714 * TLV 715 * @data: Pointer to start of the TLV 716 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 717 * @shmem_params: Pointer to MLO Global shared memory parameters. Extracted 718 * information will be populated in this data structure. 719 * 720 * Return: On success, the number of bytes parsed. On failure, -1. 721 */ 722 static int 723 extract_mlo_glb_h_shmem_tlv( 724 uint8_t *data, size_t remaining_len, 725 struct wlan_host_mlo_glb_h_shmem_params *shmem_params) 726 { 727 mlo_glb_h_shmem *ptlv; 728 uint32_t tlv_len, tlv_tag; 729 uint32_t major_minor_version; 730 731 qdf_assert_always(data); 732 qdf_assert_always(shmem_params); 733 if (process_tlv_header(data, remaining_len, 734 MLO_SHMEM_TLV_STRUCT_MLO_GLB_H_SHMEM, 735 &tlv_len, &tlv_tag) != 0) { 736 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 737 } 738 739 ptlv = (mlo_glb_h_shmem *)data; 740 major_minor_version = get_field_value_in_tlv(ptlv, major_minor_version, 741 tlv_len); 742 shmem_params->major_version = 743 MLO_SHMEM_GLB_H_SHMEM_PARAM_MAJOR_VERSION_GET( 744 major_minor_version); 745 shmem_params->minor_version = 746 MLO_SHMEM_GLB_H_SHMEM_PARAM_MINOR_VERSION_GET( 747 major_minor_version); 748 749 return tlv_len; 750 } 751 752 /** 753 * parse_mlo_glb_h_shmem_arena() - Parse MLO Global shared memory arena 754 * @data: Pointer to the first TLV in the arena 755 * @remaining_len: Length (in bytes) remaining in the arena from @data pointer 756 * @shmem_arena_ctx: Pointer to MLO Global shared memory arena context. 757 * Extracted information will be populated in this data structure. 758 * 759 * Return: On success, the number of bytes parsed. On failure, -1. 760 */ 761 static int parse_mlo_glb_h_shmem_arena( 762 uint8_t *data, size_t remaining_len, 763 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx) 764 { 765 int parsed_bytes; 766 int len; 767 768 qdf_assert_always(data); 769 qdf_assert_always(shmem_arena_ctx); 770 771 len = extract_mlo_glb_h_shmem_tlv(data, remaining_len, 772 &shmem_arena_ctx->shmem_params); 773 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 774 parsed_bytes = len; 775 776 len = extract_mlo_glb_rx_reo_snapshot_info( 777 data, remaining_len, &shmem_arena_ctx->rx_reo_snapshot_info); 778 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 779 parsed_bytes += len; 780 781 len = parse_global_link_info(data, remaining_len); 782 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 783 parsed_bytes += len; 784 785 len = extract_mlo_glb_chip_crash_info( 786 data, remaining_len, &shmem_arena_ctx->chip_crash_info); 787 validate_parsed_bytes_advance_data_pointer(len, data, remaining_len); 788 parsed_bytes += len; 789 790 return parsed_bytes; 791 } 792 793 QDF_STATUS mlo_glb_h_shmem_arena_ctx_init(void *arena_vaddr, 794 size_t arena_len, 795 uint8_t grp_id) 796 { 797 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 798 799 if (grp_id > WLAN_MAX_MLO_GROUPS) 800 return QDF_STATUS_E_INVAL; 801 802 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 803 if (!shmem_arena_ctx) { 804 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 805 return QDF_STATUS_E_NULL_VALUE; 806 } 807 808 /* We need to initialize only for the first invocation */ 809 if (qdf_atomic_read(&shmem_arena_ctx->init_count)) 810 goto success; 811 812 if (parse_mlo_glb_h_shmem_arena(arena_vaddr, arena_len, 813 shmem_arena_ctx) < 0) { 814 free_mlo_glb_rx_reo_per_link_info( 815 &shmem_arena_ctx->rx_reo_snapshot_info); 816 free_mlo_glb_per_chip_crash_info( 817 &shmem_arena_ctx->chip_crash_info); 818 return QDF_STATUS_E_FAILURE; 819 } 820 821 success: 822 qdf_atomic_inc(&shmem_arena_ctx->init_count); 823 return QDF_STATUS_SUCCESS; 824 } 825 826 qdf_export_symbol(mlo_glb_h_shmem_arena_ctx_init); 827 828 QDF_STATUS mlo_glb_h_shmem_arena_ctx_deinit(uint8_t grp_id) 829 { 830 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 831 832 if (grp_id > WLAN_MAX_MLO_GROUPS) 833 return QDF_STATUS_E_INVAL; 834 835 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 836 if (!shmem_arena_ctx) { 837 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 838 return QDF_STATUS_E_NULL_VALUE; 839 } 840 841 if (!qdf_atomic_read(&shmem_arena_ctx->init_count)) { 842 target_if_fatal("shmem_arena_ctx ref cnt is 0"); 843 return QDF_STATUS_E_FAILURE; 844 } 845 846 /* We need to de-initialize only for the last invocation */ 847 if (qdf_atomic_dec_and_test(&shmem_arena_ctx->init_count)) 848 goto success; 849 850 free_mlo_glb_rx_reo_per_link_info( 851 &shmem_arena_ctx->rx_reo_snapshot_info); 852 free_mlo_glb_per_chip_crash_info( 853 &shmem_arena_ctx->chip_crash_info); 854 855 success: 856 return QDF_STATUS_SUCCESS; 857 } 858 859 qdf_export_symbol(mlo_glb_h_shmem_arena_ctx_deinit); 860 861 #ifdef WLAN_MGMT_RX_REO_SUPPORT 862 uint16_t mgmt_rx_reo_get_valid_link_bitmap(uint8_t grp_id) 863 { 864 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 865 866 if (grp_id > WLAN_MAX_MLO_GROUPS) 867 return 0; 868 869 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 870 if (!shmem_arena_ctx) { 871 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 872 return 0; 873 } 874 875 return shmem_arena_ctx->rx_reo_snapshot_info.valid_link_bmap; 876 } 877 878 int mgmt_rx_reo_get_num_links(uint8_t grp_id) 879 { 880 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 881 882 if (grp_id > WLAN_MAX_MLO_GROUPS) 883 return -EINVAL; 884 885 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 886 if (!shmem_arena_ctx) { 887 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 888 return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); 889 } 890 891 return shmem_arena_ctx->rx_reo_snapshot_info.num_links; 892 } 893 894 void *mgmt_rx_reo_get_snapshot_address( 895 uint8_t grp_id, 896 uint8_t link_id, 897 enum mgmt_rx_reo_shared_snapshot_id snapshot_id) 898 { 899 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 900 struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info; 901 struct wlan_host_mlo_glb_rx_reo_per_link_info *snapshot_link_info; 902 uint8_t link; 903 904 if (snapshot_id >= MGMT_RX_REO_SHARED_SNAPSHOT_MAX) { 905 target_if_err("Invalid snapshot ID: %d", snapshot_id); 906 return NULL; 907 } 908 909 if (grp_id > WLAN_MAX_MLO_GROUPS) 910 return NULL; 911 912 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 913 if (!shmem_arena_ctx) { 914 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 915 return NULL; 916 } 917 918 snapshot_info = &shmem_arena_ctx->rx_reo_snapshot_info; 919 920 for (link = 0; link < snapshot_info->num_links; ++link) { 921 snapshot_link_info = &snapshot_info->link_info[link]; 922 923 if (link_id == snapshot_link_info->link_id) 924 break; 925 } 926 927 if (link == snapshot_info->num_links) { 928 target_if_err("Couldn't find the snapshot link info" 929 "corresponding to the link %d", link_id); 930 return NULL; 931 } 932 933 switch (snapshot_id) { 934 case MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW: 935 return snapshot_link_info->hw_forwarded; 936 937 case MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED: 938 return snapshot_link_info->fw_consumed; 939 940 case MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED: 941 return snapshot_link_info->fw_forwarded; 942 943 default: 944 qdf_assert_always(0); 945 } 946 947 return NULL; 948 } 949 950 int8_t mgmt_rx_reo_get_snapshot_version(uint8_t grp_id, 951 enum mgmt_rx_reo_shared_snapshot_id id) 952 { 953 struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx; 954 struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info; 955 int8_t snapshot_version; 956 957 if (id >= MGMT_RX_REO_SHARED_SNAPSHOT_MAX) { 958 target_if_err("Invalid snapshot ID: %d", id); 959 return MGMT_RX_REO_INVALID_SNAPSHOT_VERSION; 960 } 961 962 if (grp_id > WLAN_MAX_MLO_GROUPS) 963 return MGMT_RX_REO_INVALID_SNAPSHOT_VERSION; 964 965 shmem_arena_ctx = get_shmem_arena_ctx(grp_id); 966 if (!shmem_arena_ctx) { 967 target_if_err("mlo_glb_h_shmem_arena context is NULL"); 968 return MGMT_RX_REO_INVALID_SNAPSHOT_VERSION; 969 } 970 971 snapshot_info = &shmem_arena_ctx->rx_reo_snapshot_info; 972 973 switch (id) { 974 case MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW: 975 snapshot_version = snapshot_info->hw_forwarded_snapshot_ver; 976 break; 977 978 case MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED: 979 snapshot_version = snapshot_info->fw_consumed_snapshot_ver; 980 break; 981 982 case MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWARDED: 983 snapshot_version = snapshot_info->fw_forwarded_snapshot_ver; 984 break; 985 986 default: 987 snapshot_version = MGMT_RX_REO_INVALID_SNAPSHOT_VERSION; 988 break; 989 } 990 991 return snapshot_version; 992 } 993 #endif /* WLAN_MGMT_RX_REO_SUPPORT */ 994