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