xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/mlo_global_h_shmem_arena.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  *  DOC: mlo_global_h_shmem_arena.c
19  *  This file contains definition of functions that parse the MLO global
20  *  shared memory arena.
21  */
22 
23 #include<mlo_global_h_shmem_arena.h>
24 
25 static struct wlan_host_mlo_glb_h_shmem_arena_ctx g_shmem_arena_ctx;
26 
27 #define get_shmem_arena_ctx() (&g_shmem_arena_ctx)
28 
29 /**
30  * get_field_value_in_tlv() - Get the value of a given field in a given TLV
31  * @ptlv: Pointer to start of the TLV
32  * @field_name: name of the field in the TLV structure
33  * @tlv_len: Length of the TLV
34  *
35  * Return: Value of the given field if the offset of the field with in the TLV
36  * structure is less than the TLV length, else 0.
37  */
38 #define get_field_value_in_tlv(ptlv, field_name, tlv_len) \
39 	(qdf_offsetof(typeof(*(ptlv)), field_name) < (tlv_len) ? \
40 		(ptlv)->field_name : 0)
41 
42 /**
43  * get_field_pointer_in_tlv() - Get the address of a given field in a given TLV
44  * @ptlv: Pointer to start of the TLV
45  * @field_name: name of the field in the TLV structure
46  * @tlv_len: Length of the TLV
47  *
48  * Return: Address of the given field if the offset of the field with in the
49  * TLV structure is less than the TLV length, else NULL.
50  */
51 #define get_field_pointer_in_tlv(ptlv, field_name, tlv_len) \
52 	(qdf_offsetof(typeof(*(ptlv)), field_name) < (tlv_len) ? \
53 		&(ptlv)->field_name : NULL)
54 
55 /**
56  * process_tlv_header() - Process a given TLV header
57  * @data: Pointer to start of the TLV
58  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
59  * @expected_tag: Expected TLV tag
60  * @tlv_len: Address of TLV length variable to be populated. This API populates
61  * the entire length(payload + header) of the TLV into @tlv_len
62  * @tlv_tag: Address of TLV Tag variable to be populated.
63  *
64  * Return: 0 on success, -1 on failure
65  */
66 static int
67 process_tlv_header(const uint8_t *data, size_t remaining_len,
68 		   uint32_t expected_tag, uint32_t *tlv_len,
69 		   uint32_t *tlv_tag)
70 {
71 	if (remaining_len < MLO_SHMEM_TLV_HDR_SIZE) {
72 		target_if_err("Not enough space(%zu) to read TLV header(%u)",
73 			      remaining_len, (uint32_t)MLO_SHMEM_TLV_HDR_SIZE);
74 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
75 	}
76 
77 	*tlv_len = MLO_SHMEMTLV_GET_TLVLEN(MLO_SHMEMTLV_GET_HDR(data));
78 	*tlv_len += MLO_SHMEM_TLV_HDR_SIZE;
79 	if (remaining_len < *tlv_len) {
80 		target_if_err("Not enough space(%zu) to read TLV payload(%u)",
81 			      remaining_len, *tlv_len);
82 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
83 	}
84 
85 	*tlv_tag = MLO_SHMEMTLV_GET_TLVTAG(MLO_SHMEMTLV_GET_HDR(data));
86 	if (*tlv_tag != expected_tag) {
87 		target_if_err("Unexpected TLV tag: %u is seen. Expected: %u",
88 			      *tlv_tag,
89 			      expected_tag);
90 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
91 	}
92 
93 	return 0;
94 }
95 
96 #define validate_parsed_bytes_advance_data_pointer(parsed_bytes, data, \
97 						   remaining_len) \
98 do { \
99 	if ((parsed_bytes) < 0) { \
100 		target_if_err("TLV extraction failed"); \
101 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); \
102 	} \
103 	(data) += (parsed_bytes); \
104 	(remaining_len) -= (parsed_bytes); \
105 } while (0)
106 
107 /**
108  * extract_mgmt_rx_reo_snapshot_tlv() - extract MGMT_RX_REO_SNAPSHOT TLV
109  * @data: Pointer to start of the TLV
110  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
111  * @address_ptr: Pointer to the snapshot address. This API will populate the
112  * snapshot address into the variable pointed by @address_ptr
113  *
114  * Return: On success, the number of bytes parsed. On failure, -1.
115  */
116 static int
117 extract_mgmt_rx_reo_snapshot_tlv(uint8_t *data, size_t remaining_len,
118 				 void **address_ptr)
119 {
120 	mgmt_rx_reo_snapshot *ptlv;
121 	uint32_t tlv_len, tlv_tag;
122 
123 	qdf_assert_always(data);
124 	qdf_assert_always(address_ptr);
125 
126 	/* process MLO_SHMEM_TLV_STRUCT_MGMT_RX_REO_SNAPSHOT TLV */
127 	if (process_tlv_header(data, remaining_len,
128 			       MLO_SHMEM_TLV_STRUCT_MGMT_RX_REO_SNAPSHOT,
129 			       &tlv_len, &tlv_tag) != 0) {
130 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
131 	}
132 
133 	ptlv = (mgmt_rx_reo_snapshot *)data;
134 	*address_ptr = get_field_pointer_in_tlv(ptlv, mgmt_rx_reo_snapshot_low,
135 						tlv_len);
136 
137 	return tlv_len;
138 }
139 
140 /**
141  * extract_mlo_glb_rx_reo_per_link_info_tlv() - extract
142  * RX_REO_PER_LINK_SNAPSHOT_INFO TLV
143  * @data: Pointer to start of the TLV
144  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
145  * @link_info: Pointer to MGMT Rx REO per link info. Extracted information
146  * will be populated in this data structure.
147  *
148  * Return: On success, the number of bytes parsed. On failure, -1.
149  */
150 static int
151 extract_mlo_glb_rx_reo_per_link_info_tlv(
152 	uint8_t *data, size_t remaining_len, uint8_t link_id,
153 	struct wlan_host_mlo_glb_rx_reo_per_link_info *link_info)
154 {
155 	mlo_glb_rx_reo_per_link_snapshot_info *ptlv;
156 	uint32_t tlv_len, tlv_tag;
157 	int len;
158 	uint8_t *fw_consumed;
159 
160 	qdf_assert_always(data);
161 	qdf_assert_always(link_info);
162 
163 	/* process MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_PER_LINK_SNAPSHOT_INFO TLV */
164 	if (process_tlv_header(data, remaining_len,
165 			       MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_PER_LINK_SNAPSHOT_INFO,
166 			       &tlv_len, &tlv_tag) != 0) {
167 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
168 	}
169 
170 	ptlv = (mlo_glb_rx_reo_per_link_snapshot_info *)data;
171 
172 	link_info->link_id = link_id;
173 
174 	/**
175 	 * Get the pointer to the fw_consumed snapshot with in the TLV.
176 	 * Note that snapshots are nested TLVs within link_sanpshot_info TLV.
177 	 */
178 	fw_consumed = (uint8_t *)get_field_pointer_in_tlv(ptlv, fw_consumed,
179 							  tlv_len);
180 	remaining_len -= qdf_offsetof(mlo_glb_rx_reo_per_link_snapshot_info,
181 				      fw_consumed);
182 
183 	/* extract fw_consumed snapshot */
184 	len = extract_mgmt_rx_reo_snapshot_tlv(fw_consumed, remaining_len,
185 					       &link_info->fw_consumed);
186 	validate_parsed_bytes_advance_data_pointer(len, data, remaining_len);
187 
188 	/* extract fw_forwarded snapshot */
189 	len = extract_mgmt_rx_reo_snapshot_tlv(fw_consumed, remaining_len,
190 					       &link_info->fw_forwarded);
191 	validate_parsed_bytes_advance_data_pointer(len, data, remaining_len);
192 
193 	/* extract hw_forwarded snapshot */
194 	len = extract_mgmt_rx_reo_snapshot_tlv(fw_consumed, remaining_len,
195 					       &link_info->hw_forwarded);
196 	validate_parsed_bytes_advance_data_pointer(len, data, remaining_len);
197 
198 	/**
199 	 * Return the length of link_sanpshot_info TLV itself as the snapshots
200 	 * are nested inside link_sanpshot_info TLV and hence no need to add
201 	 * their lengths separately.
202 	 */
203 	return tlv_len;
204 }
205 
206 /**
207  * get_num_links_from_valid_link_bitmap() - Get the number of valid links
208  * @valid_link_bmap: Link bit map where the valid links are set to 1
209  *
210  * Return: Number of valid links
211  */
212 static uint8_t
213 get_num_links_from_valid_link_bitmap(uint16_t valid_link_bmap)
214 {
215 	uint8_t num_links = 0;
216 
217 	/* Find the number of set bits */
218 	while (valid_link_bmap) {
219 		num_links++;
220 		valid_link_bmap &= (valid_link_bmap - 1);
221 	}
222 
223 	return num_links;
224 }
225 
226 /**
227  * extract_mlo_glb_rx_reo_snapshot_info_tlv() - extract
228  * MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO TLV
229  * @data: Pointer to start of the TLV
230  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
231  * @snapshot_info: Pointer to MGMT Rx REO snapshot info. Extracted information
232  * will be populated in this data structure.
233  *
234  * Return: On success, the number of bytes parsed. On failure, -1.
235  */
236 static int
237 extract_mlo_glb_rx_reo_snapshot_info_tlv(
238 	uint8_t *data, size_t remaining_len,
239 	struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info)
240 {
241 	mlo_glb_rx_reo_snapshot_info *ptlv;
242 	uint32_t tlv_len, tlv_tag;
243 	uint32_t link_info;
244 	uint16_t valid_link_bmap;
245 
246 	qdf_assert_always(data);
247 	qdf_assert_always(snapshot_info);
248 
249 	/* process MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO TLV */
250 	if (process_tlv_header(data, remaining_len,
251 			       MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO,
252 			       &tlv_len, &tlv_tag) != 0) {
253 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
254 	}
255 
256 	ptlv = (mlo_glb_rx_reo_snapshot_info *)data;
257 	link_info = get_field_value_in_tlv(ptlv, link_info, tlv_len);
258 	valid_link_bmap =
259 		MLO_SHMEM_GLB_LINK_INFO_PARAM_VALID_LINK_BMAP_GET(link_info);
260 
261 	snapshot_info->valid_link_bmap = valid_link_bmap;
262 	snapshot_info->num_links =
263 			get_num_links_from_valid_link_bitmap(valid_link_bmap);
264 	snapshot_info->link_info = qdf_mem_malloc(
265 					sizeof(*snapshot_info->link_info) *
266 					snapshot_info->num_links);
267 	if (!snapshot_info->link_info) {
268 		target_if_err("Couldn't allocate memory for rx_reo_per_link_info");
269 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
270 	}
271 
272 	return tlv_len;
273 }
274 
275 /**
276  * free_mlo_glb_rx_reo_per_link_info() - Free Rx REO per-link info
277  * @snapshot_info: Pointer to MGMT Rx REO snapshot info
278  *
279  * Return: None
280  */
281 static void free_mlo_glb_rx_reo_per_link_info(
282 	struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info)
283 {
284 	if (snapshot_info && snapshot_info->link_info) {
285 		qdf_mem_free(snapshot_info->link_info);
286 		snapshot_info->link_info =  NULL;
287 	}
288 }
289 
290 /**
291  * get_next_valid_link_id() - Get next valid link ID
292  * @valid_link_bmap: Link bit map where the valid links are set to 1
293  * @prev_link_id: Previous link ID
294  *
295  * Return: Next valid link ID if there are valid links after @prev_link_id,
296  * else -1
297  */
298 static int
299 get_next_valid_link_id(uint16_t valid_link_bmap, int prev_link_id)
300 {
301 	int cur_link_id;
302 	uint16_t mask;
303 	uint8_t maxbits = sizeof(valid_link_bmap) * QDF_CHAR_BIT;
304 
305 	cur_link_id = prev_link_id + 1;
306 	mask = 1 << cur_link_id;
307 
308 	while (!(valid_link_bmap & mask)) {
309 		cur_link_id++;
310 		if (cur_link_id == maxbits)
311 			return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
312 		mask = mask << 1;
313 	}
314 
315 	return cur_link_id;
316 }
317 
318 /**
319  * extract_mlo_glb_rx_reo_snapshot_info() - extract MGMT Rx REO snapshot info
320  * @data: Pointer to start of MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO
321  * TLV
322  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
323  * @snapshot_info: Pointer to MGMT Rx REO snapshot info. Extracted information
324  * will be populated in this data structure.
325  *
326  * Return: On success, the number of bytes parsed. On failure, -1.
327  */
328 static int
329 extract_mlo_glb_rx_reo_snapshot_info(
330 	uint8_t *data, size_t remaining_len,
331 	struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info)
332 {
333 	int parsed_bytes, len;
334 	uint8_t link;
335 	int cur_link_id, prev_link_id = -1;
336 	uint16_t valid_link_bmap;
337 
338 	qdf_assert_always(data);
339 	qdf_assert_always(snapshot_info);
340 
341 	/* Extract MLO_SHMEM_TLV_STRUCT_MLO_GLB_RX_REO_SNAPSHOT_INFO TLV */
342 	len = extract_mlo_glb_rx_reo_snapshot_info_tlv(data, remaining_len,
343 						       snapshot_info);
344 	validate_parsed_bytes_advance_data_pointer(len, data, remaining_len);
345 	parsed_bytes = len;
346 
347 	valid_link_bmap = snapshot_info->valid_link_bmap;
348 	/* Foreach valid link */
349 	for (link = 0; link < snapshot_info->num_links; ++link) {
350 		cur_link_id = get_next_valid_link_id(valid_link_bmap,
351 						     prev_link_id);
352 
353 		qdf_assert_always(cur_link_id >= 0);
354 
355 		/* Extract per_link_info */
356 		len  = extract_mlo_glb_rx_reo_per_link_info_tlv(
357 					data, remaining_len, cur_link_id,
358 					&snapshot_info->link_info[link]);
359 		validate_parsed_bytes_advance_data_pointer(len, data,
360 							   remaining_len);
361 		parsed_bytes += len;
362 		prev_link_id = cur_link_id;
363 	}
364 
365 	return parsed_bytes;
366 }
367 
368 /**
369  * extract_mlo_glb_h_shmem_tlv() - extract MLO_SHMEM_TLV_STRUCT_MLO_GLB_H_SHMEM
370  * TLV
371  * @data: Pointer to start of the TLV
372  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
373  * @shmem_params: Pointer to MLO Global shared memory parameters. Extracted
374  * information will be populated in this data structure.
375  *
376  * Return: On success, the number of bytes parsed. On failure, -1.
377  */
378 static int
379 extract_mlo_glb_h_shmem_tlv(
380 		uint8_t *data, size_t remaining_len,
381 		struct wlan_host_mlo_glb_h_shmem_params *shmem_params)
382 {
383 	mlo_glb_h_shmem *ptlv;
384 	uint32_t tlv_len, tlv_tag;
385 	uint32_t major_minor_version;
386 
387 	qdf_assert_always(data);
388 	qdf_assert_always(shmem_params);
389 	if (process_tlv_header(data, remaining_len,
390 			       MLO_SHMEM_TLV_STRUCT_MLO_GLB_H_SHMEM,
391 			       &tlv_len, &tlv_tag) != 0) {
392 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
393 	}
394 
395 	ptlv = (mlo_glb_h_shmem *)data;
396 	major_minor_version = get_field_value_in_tlv(ptlv, major_minor_version,
397 						     tlv_len);
398 	shmem_params->major_version =
399 			MLO_SHMEM_GLB_H_SHMEM_PARAM_MAJOR_VERSION_GET(
400 				major_minor_version);
401 	shmem_params->minor_version =
402 			MLO_SHMEM_GLB_H_SHMEM_PARAM_MINOR_VERSION_GET(
403 				major_minor_version);
404 
405 	return tlv_len;
406 }
407 
408 /**
409  * parse_mlo_glb_h_shmem_arena() - Parse MLO Global shared memory arena
410  * @data: Pointer to the first TLV in the arena
411  * @remaining_len: Length (in bytes) remaining in the arena from @data pointer
412  * @shmem_arena_ctx: Pointer to MLO Global shared memory arena context.
413  * Extracted information will be populated in this data structure.
414  *
415  * Return: On success, the number of bytes parsed. On failure, -1.
416  */
417 static int parse_mlo_glb_h_shmem_arena(
418 	uint8_t *data, size_t remaining_len,
419 	struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx)
420 {
421 	int parsed_bytes, len;
422 
423 	qdf_assert_always(data);
424 	qdf_assert_always(shmem_arena_ctx);
425 
426 	len = extract_mlo_glb_h_shmem_tlv(data, remaining_len,
427 					  &shmem_arena_ctx->shmem_params);
428 	validate_parsed_bytes_advance_data_pointer(len, data, remaining_len);
429 	parsed_bytes += len;
430 
431 	len = extract_mlo_glb_rx_reo_snapshot_info(
432 		data, remaining_len, &shmem_arena_ctx->rx_reo_snapshot_info);
433 	validate_parsed_bytes_advance_data_pointer(len, data, remaining_len);
434 	parsed_bytes += len;
435 
436 	return parsed_bytes;
437 }
438 
439 QDF_STATUS mlo_glb_h_shmem_arena_ctx_init(uint8_t *arena_vaddr,
440 					  size_t arena_len)
441 {
442 	struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx;
443 
444 	shmem_arena_ctx = get_shmem_arena_ctx();
445 	if (!shmem_arena_ctx) {
446 		target_if_err("mlo_glb_h_shmem_arena context is NULL");
447 		return QDF_STATUS_E_NULL_VALUE;
448 	}
449 
450 	/* We need to initialize only for the first invocation */
451 	if (qdf_atomic_read(&shmem_arena_ctx->init_count))
452 		goto success;
453 
454 	if (parse_mlo_glb_h_shmem_arena(arena_vaddr, arena_len,
455 					shmem_arena_ctx) < 0) {
456 		free_mlo_glb_rx_reo_per_link_info(
457 			&shmem_arena_ctx->rx_reo_snapshot_info);
458 		return QDF_STATUS_E_FAILURE;
459 	}
460 
461 success:
462 	qdf_atomic_inc(&shmem_arena_ctx->init_count);
463 	return QDF_STATUS_SUCCESS;
464 }
465 
466 QDF_STATUS mlo_glb_h_shmem_arena_deinit(void)
467 {
468 	struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx;
469 
470 	shmem_arena_ctx = get_shmem_arena_ctx();
471 	if (!shmem_arena_ctx) {
472 		target_if_err("mlo_glb_h_shmem_arena context is NULL");
473 		return QDF_STATUS_E_NULL_VALUE;
474 	}
475 
476 	if (!qdf_atomic_read(&shmem_arena_ctx->init_count)) {
477 		target_if_fatal("shmem_arena_ctx ref cnt is 0");
478 		return QDF_STATUS_E_FAILURE;
479 	}
480 
481 	/* We need to de-initialize only for the last invocation */
482 	if (qdf_atomic_dec_and_test(&shmem_arena_ctx->init_count))
483 		goto success;
484 
485 	free_mlo_glb_rx_reo_per_link_info(
486 		&shmem_arena_ctx->rx_reo_snapshot_info);
487 
488 success:
489 	return QDF_STATUS_SUCCESS;
490 }
491 
492 int mgmt_rx_reo_get_num_links(void)
493 {
494 	struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx;
495 
496 	shmem_arena_ctx = get_shmem_arena_ctx();
497 	if (!shmem_arena_ctx) {
498 		target_if_err("mlo_glb_h_shmem_arena context is NULL");
499 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
500 	}
501 
502 	return shmem_arena_ctx->rx_reo_snapshot_info.num_links;
503 }
504 
505 void *mgmt_rx_reo_get_snapshot_address(
506 	uint8_t link_id, enum mgmt_rx_reo_shared_snapshot_id snapshot_id)
507 {
508 	struct wlan_host_mlo_glb_h_shmem_arena_ctx *shmem_arena_ctx;
509 	struct wlan_host_mlo_glb_rx_reo_snapshot_info *snapshot_info;
510 	struct wlan_host_mlo_glb_rx_reo_per_link_info *snapshot_link_info;
511 	uint8_t link;
512 
513 	if (snapshot_id >= MGMT_RX_REO_SHARED_SNAPSHOT_MAX) {
514 		target_if_err("Invalid snapshot ID: %d", snapshot_id);
515 		return NULL;
516 	}
517 
518 	shmem_arena_ctx = get_shmem_arena_ctx();
519 	if (!shmem_arena_ctx) {
520 		target_if_err("mlo_glb_h_shmem_arena context is NULL");
521 		return NULL;
522 	}
523 
524 	snapshot_info = &shmem_arena_ctx->rx_reo_snapshot_info;
525 
526 	for (link = 0; link < snapshot_info->num_links; ++link) {
527 		snapshot_link_info = &snapshot_info->link_info[link];
528 
529 		if (link_id == snapshot_link_info->link_id)
530 			break;
531 	}
532 
533 	if (link == snapshot_info->num_links) {
534 		target_if_err("Couldn't find the snapshot link info"
535 			      "corresponding to the link %d", link_id);
536 		return NULL;
537 	}
538 
539 	switch (snapshot_id) {
540 	case MGMT_RX_REO_SHARED_SNAPSHOT_MAC_HW:
541 		return snapshot_link_info->hw_forwarded;
542 
543 	case MGMT_RX_REO_SHARED_SNAPSHOT_FW_CONSUMED:
544 		return snapshot_link_info->fw_consumed;
545 
546 	case MGMT_RX_REO_SHARED_SNAPSHOT_FW_FORWADED:
547 		return snapshot_link_info->fw_forwarded;
548 
549 	default:
550 		qdf_assert_always(0);
551 	}
552 
553 	return NULL;
554 }
555