xref: /wlan-dirver/qca-wifi-host-cmn/hal/wifi3.0/hal_rx_flow.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2019-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 #include "qdf_module.h"
18 #include "dp_types.h"
19 #include "hal_rx_flow.h"
20 
21 /**
22  * hal_rx_flow_get_cmem_fse() - Get FSE from CMEM
23  * @hal_soc_hdl: HAL SOC handle
24  * @fse_offset: CMEM FSE offset
25  * @fse: referece where FSE will be copied
26  * @len: length of FSE
27  *
28  * Return: If read is succesfull or not
29  */
30 static void
31 hal_rx_flow_get_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t fse_offset,
32 			 uint32_t *fse, qdf_size_t len)
33 {
34 	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
35 
36 	if (hal_soc->ops->hal_rx_flow_get_cmem_fse) {
37 		return hal_soc->ops->hal_rx_flow_get_cmem_fse(
38 						hal_soc, fse_offset, fse, len);
39 	}
40 }
41 
42 #if defined(WLAN_SUPPORT_RX_FISA)
43 static inline void hal_rx_dump_fse(struct rx_flow_search_entry *fse, int index)
44 {
45 		dp_info("index %d:"
46 		" src_ip_127_96 0x%x"
47 		" src_ip_95_640 0x%x"
48 		" src_ip_63_32 0x%x"
49 		" src_ip_31_0 0x%x"
50 		" dest_ip_127_96 0x%x"
51 		" dest_ip_95_64 0x%x"
52 		" dest_ip_63_32 0x%x"
53 		" dest_ip_31_0 0x%x"
54 		" src_port 0x%x"
55 		" dest_port 0x%x"
56 		" l4_protocol 0x%x"
57 		" valid 0x%x"
58 		" reo_destination_indication 0x%x"
59 		" msdu_drop 0x%x"
60 		" reo_destination_handler 0x%x"
61 		" metadata 0x%x"
62 		" aggregation_count0x%x"
63 		" lro_eligible 0x%x"
64 		" msdu_count 0x%x"
65 		" msdu_byte_count 0x%x"
66 		" timestamp 0x%x"
67 		" cumulative_l4_checksum 0x%x"
68 		" cumulative_ip_length 0x%x"
69 		" tcp_sequence_number 0x%x",
70 		index,
71 		fse->src_ip_127_96,
72 		fse->src_ip_95_64,
73 		fse->src_ip_63_32,
74 		fse->src_ip_31_0,
75 		fse->dest_ip_127_96,
76 		fse->dest_ip_95_64,
77 		fse->dest_ip_63_32,
78 		fse->dest_ip_31_0,
79 		fse->src_port,
80 		fse->dest_port,
81 		fse->l4_protocol,
82 		fse->valid,
83 		fse->reo_destination_indication,
84 		fse->msdu_drop,
85 		fse->reo_destination_handler,
86 		fse->metadata,
87 		fse->aggregation_count,
88 		fse->lro_eligible,
89 		fse->msdu_count,
90 		fse->msdu_byte_count,
91 		fse->timestamp,
92 		fse->cumulative_l4_checksum,
93 		fse->cumulative_ip_length,
94 		fse->tcp_sequence_number);
95 }
96 
97 void hal_rx_dump_fse_table(struct hal_rx_fst *fst)
98 {
99 	int i = 0;
100 	struct rx_flow_search_entry *fse =
101 		(struct rx_flow_search_entry *)fst->base_vaddr;
102 
103 	dp_info("Number flow table entries %d", fst->add_flow_count);
104 	for (i = 0; i < fst->max_entries; i++) {
105 		if (fse[i].valid)
106 			hal_rx_dump_fse(&fse[i], i);
107 	}
108 }
109 
110 void hal_rx_dump_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t fse_offset,
111 			  int index)
112 {
113 	struct rx_flow_search_entry fse = {0};
114 
115 	if (!fse_offset)
116 		return;
117 
118 	hal_rx_flow_get_cmem_fse(hal_soc_hdl, fse_offset, (uint32_t *)&fse,
119 				 sizeof(struct rx_flow_search_entry));
120 	if (fse.valid)
121 		hal_rx_dump_fse(&fse, index);
122 }
123 #else
124 void hal_rx_dump_fse_table(struct hal_rx_fst *fst)
125 {
126 }
127 
128 void hal_rx_dump_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t fse_offset,
129 			  int index)
130 {
131 }
132 #endif
133 
134 /**
135  * hal_rx_flow_setup_fse() - Setup a flow search entry in HW FST
136  * @fst: Pointer to the Rx Flow Search Table
137  * @table_offset: offset into the table where the flow is to be setup
138  * @flow: Flow Parameters
139  *
140  * Return: Success/Failure
141  */
142 void *
143 hal_rx_flow_setup_fse(hal_soc_handle_t hal_soc_hdl,
144 		      struct hal_rx_fst *fst, uint32_t table_offset,
145 		      struct hal_rx_flow *flow)
146 {
147 	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
148 
149 	if (hal_soc->ops->hal_rx_flow_setup_fse) {
150 		return hal_soc->ops->hal_rx_flow_setup_fse((uint8_t *)fst,
151 							   table_offset,
152 							   (uint8_t *)flow);
153 	}
154 
155 	return NULL;
156 }
157 qdf_export_symbol(hal_rx_flow_setup_fse);
158 
159 /**
160  * hal_rx_flow_setup_cmem_fse() - Setup a flow search entry in HW CMEM FST
161  * @hal_soc_hdl: HAL SOC handle
162  * @cmem_ba: CMEM base address
163  * @table_offset: offset into the table where the flow is to be setup
164  * @flow: Flow Parameters
165  *
166  * Return: Success/Failure
167  */
168 uint32_t
169 hal_rx_flow_setup_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t cmem_ba,
170 			   uint32_t table_offset, struct hal_rx_flow *flow)
171 {
172 	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
173 
174 	if (hal_soc->ops->hal_rx_flow_setup_cmem_fse) {
175 		return hal_soc->ops->hal_rx_flow_setup_cmem_fse(
176 						hal_soc, cmem_ba,
177 						table_offset, (uint8_t *)flow);
178 	}
179 
180 	return 0;
181 }
182 qdf_export_symbol(hal_rx_flow_setup_cmem_fse);
183 
184 /**
185  * hal_rx_flow_get_cmem_fse_timestamp() - Get timestamp field from CMEM FSE
186  * @hal_soc_hdl: HAL SOC handle
187  * @fse_offset: CMEM FSE offset
188  *
189  * Return: Timestamp
190  */
191 uint32_t hal_rx_flow_get_cmem_fse_timestamp(hal_soc_handle_t hal_soc_hdl,
192 					    uint32_t fse_offset)
193 {
194 	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
195 
196 	if (hal_soc->ops->hal_rx_flow_get_cmem_fse_ts) {
197 		return hal_soc->ops->hal_rx_flow_get_cmem_fse_ts(hal_soc,
198 								 fse_offset);
199 	}
200 
201 	return 0;
202 }
203 qdf_export_symbol(hal_rx_flow_get_cmem_fse_timestamp);
204 
205 /**
206  * hal_rx_flow_delete_entry() - Delete a flow from the Rx Flow Search Table
207  * @fst: Pointer to the Rx Flow Search Table
208  * @hal_rx_fse: Pointer to the Rx Flow that is to be deleted from the FST
209  *
210  * Return: Success/Failure
211  */
212 QDF_STATUS
213 hal_rx_flow_delete_entry(struct hal_rx_fst *fst, void *hal_rx_fse)
214 {
215 	uint8_t *fse = (uint8_t *)hal_rx_fse;
216 
217 	if (!HAL_GET_FLD(fse, HAL_RX_FLOW_SEARCH_ENTRY, VALID))
218 		return QDF_STATUS_E_NOENT;
219 
220 	HAL_CLR_FLD(fse, HAL_RX_FLOW_SEARCH_ENTRY, VALID);
221 
222 	return QDF_STATUS_SUCCESS;
223 }
224 qdf_export_symbol(hal_rx_flow_delete_entry);
225 
226 #ifndef WLAN_SUPPORT_RX_FISA
227 /**
228  * hal_rx_fst_key_configure() - Configure the Toeplitz key in the FST
229  * @fst: Pointer to the Rx Flow Search Table
230  *
231  * Return: Success/Failure
232  */
233 static void hal_rx_fst_key_configure(struct hal_rx_fst *fst)
234 {
235 	uint8_t key_bytes[HAL_FST_HASH_KEY_SIZE_BYTES];
236 
237 	qdf_mem_copy(key_bytes, fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
238 
239 	/**
240 	 * The Toeplitz algorithm as per the Microsoft spec works in a
241 	 * “big-endian” manner, using the MSBs of the key to hash the
242 	 * initial bytes of the input going on to use up the lower order bits
243 	 * of the key to hash further bytes of the input until the LSBs of the
244 	 * key are used finally.
245 	 *
246 	 * So first, rightshift 320-bit input key 5 times to get 315 MS bits
247 	 */
248 	key_bitwise_shift_left(key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES, 5);
249 	key_reverse(fst->shifted_key, key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES);
250 }
251 #else
252 static void hal_rx_fst_key_configure(struct hal_rx_fst *fst)
253 {
254 }
255 #endif
256 
257 /**
258  * hal_rx_fst_get_base() - Retrieve the virtual base address of the Rx FST
259  * @fst: Pointer to the Rx Flow Search Table
260  *
261  * Return: Success/Failure
262  */
263 static inline void *hal_rx_fst_get_base(struct hal_rx_fst *fst)
264 {
265 	return fst->base_vaddr;
266 }
267 
268 /**
269  * hal_rx_fst_get_fse_size() - Retrieve the size of each entry(flow) in Rx FST
270  *
271  * Return: size of each entry/flow in Rx FST
272  */
273 static inline uint32_t hal_rx_fst_get_fse_size(void)
274 {
275 	return HAL_RX_FST_ENTRY_SIZE;
276 }
277 
278 /**
279  * hal_rx_flow_get_tuple_info() - Retrieve the 5-tuple flow info for an entry
280  * @hal_fse: Pointer to the Flow in Rx FST
281  * @tuple_info: 5-tuple info of the flow returned to the caller
282  *
283  * Return: Success/Failure
284  */
285 QDF_STATUS hal_rx_flow_get_tuple_info(void *hal_fse,
286 				      struct hal_flow_tuple_info *tuple_info)
287 {
288 	if (!hal_fse || !tuple_info)
289 		return QDF_STATUS_E_INVAL;
290 
291 	if (!HAL_GET_FLD(hal_fse, HAL_RX_FLOW_SEARCH_ENTRY, VALID))
292 		return QDF_STATUS_E_NOENT;
293 
294 	tuple_info->src_ip_127_96 =
295 				qdf_ntohl(HAL_GET_FLD(hal_fse,
296 						      HAL_RX_FLOW_SEARCH_ENTRY,
297 						      SRC_IP_127_96));
298 	tuple_info->src_ip_95_64 =
299 				qdf_ntohl(HAL_GET_FLD(hal_fse,
300 						      HAL_RX_FLOW_SEARCH_ENTRY,
301 						      SRC_IP_95_64));
302 	tuple_info->src_ip_63_32 =
303 				qdf_ntohl(HAL_GET_FLD(hal_fse,
304 						      HAL_RX_FLOW_SEARCH_ENTRY,
305 						      SRC_IP_63_32));
306 	tuple_info->src_ip_31_0 =
307 				qdf_ntohl(HAL_GET_FLD(hal_fse,
308 						      HAL_RX_FLOW_SEARCH_ENTRY,
309 						      SRC_IP_31_0));
310 	tuple_info->dest_ip_127_96 =
311 				qdf_ntohl(HAL_GET_FLD(hal_fse,
312 						      HAL_RX_FLOW_SEARCH_ENTRY,
313 						      DEST_IP_127_96));
314 	tuple_info->dest_ip_95_64 =
315 				qdf_ntohl(HAL_GET_FLD(hal_fse,
316 						      HAL_RX_FLOW_SEARCH_ENTRY,
317 						      DEST_IP_95_64));
318 	tuple_info->dest_ip_63_32 =
319 				qdf_ntohl(HAL_GET_FLD(hal_fse,
320 						      HAL_RX_FLOW_SEARCH_ENTRY,
321 						      DEST_IP_63_32));
322 	tuple_info->dest_ip_31_0 =
323 			qdf_ntohl(HAL_GET_FLD(hal_fse,
324 					      HAL_RX_FLOW_SEARCH_ENTRY,
325 					      DEST_IP_31_0));
326 	tuple_info->dest_port = HAL_GET_FLD(hal_fse,
327 					    HAL_RX_FLOW_SEARCH_ENTRY,
328 					    DEST_PORT);
329 	tuple_info->src_port = HAL_GET_FLD(hal_fse,
330 					   HAL_RX_FLOW_SEARCH_ENTRY,
331 					   SRC_PORT);
332 	tuple_info->l4_protocol = HAL_GET_FLD(hal_fse,
333 					      HAL_RX_FLOW_SEARCH_ENTRY,
334 					      L4_PROTOCOL);
335 
336 	return QDF_STATUS_SUCCESS;
337 }
338 
339 #ifndef WLAN_SUPPORT_RX_FISA
340 /**
341  * hal_flow_toeplitz_create_cache() - Calculate hashes for each possible
342  * byte value with the key taken as is
343  *
344  * @fst: FST Handle
345  * @key: Hash Key
346  *
347  * Return: Success/Failure
348  */
349 static void hal_flow_toeplitz_create_cache(struct hal_rx_fst *fst)
350 {
351 	int bit;
352 	int val;
353 	int i;
354 	uint8_t *key = fst->shifted_key;
355 
356 	/*
357 	 * Initialise to first 32 bits of the key; shift in further key material
358 	 * through the loop
359 	 */
360 	uint32_t cur_key = (key[0] << 24) | (key[1] << 16) | (key[2] << 8) |
361 		key[3];
362 
363 	for (i = 0; i < HAL_FST_HASH_KEY_SIZE_BYTES; i++) {
364 		uint8_t new_key_byte;
365 		uint32_t shifted_key[8];
366 
367 		if (i + 4 < HAL_FST_HASH_KEY_SIZE_BYTES)
368 			new_key_byte = key[i + 4];
369 		else
370 			new_key_byte = 0;
371 
372 		shifted_key[0] = cur_key;
373 
374 		for (bit = 1; bit < 8; bit++) {
375 			/*
376 			 * For each iteration, shift out one more bit of the
377 			 * current key and shift in one more bit of the new key
378 			 * material
379 			 */
380 			shifted_key[bit] = cur_key << bit |
381 				new_key_byte >> (8 - bit);
382 		}
383 
384 		for (val = 0; val < (1 << 8); val++) {
385 			uint32_t hash = 0;
386 			int mask;
387 
388 			/*
389 			 * For each bit set in the input, XOR in
390 			 * the appropriately shifted key
391 			 */
392 			for (bit = 0, mask = 1 << 7; bit < 8; bit++, mask >>= 1)
393 				if ((val & mask))
394 					hash ^= shifted_key[bit];
395 
396 			fst->key_cache[i][val] = hash;
397 		}
398 
399 		cur_key = cur_key << 8 | new_key_byte;
400 	}
401 }
402 #else
403 static void hal_flow_toeplitz_create_cache(struct hal_rx_fst *fst)
404 {
405 }
406 #endif
407 
408 /**
409  * hal_rx_fst_attach() - Initialize Rx flow search table in HW FST
410  *
411  * @qdf_dev: QDF device handle
412  * @hal_fst_base_paddr: Pointer to the physical base address of the Rx FST
413  * @max_entries: Max number of flows allowed in the FST
414  * @max_search: Number of collisions allowed in the hash-based FST
415  * @hash_key: Toeplitz key used for the hash FST
416  *
417  * Return:
418  */
419 struct hal_rx_fst *
420 hal_rx_fst_attach(qdf_device_t qdf_dev,
421 		  uint64_t *hal_fst_base_paddr, uint16_t max_entries,
422 		  uint16_t max_search, uint8_t *hash_key)
423 {
424 	struct hal_rx_fst *fst = qdf_mem_malloc(sizeof(struct hal_rx_fst));
425 
426 	if (!fst) {
427 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
428 			  FL("hal fst allocation failed,"));
429 		return NULL;
430 	}
431 
432 	qdf_mem_set(fst, sizeof(struct hal_rx_fst), 0);
433 
434 	fst->key = hash_key;
435 	fst->max_skid_length = max_search;
436 	fst->max_entries = max_entries;
437 	fst->hash_mask = max_entries - 1;
438 
439 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
440 		  "HAL FST allocation %pK %d * %d\n", fst,
441 		  fst->max_entries, HAL_RX_FST_ENTRY_SIZE);
442 
443 	fst->base_vaddr = (uint8_t *)qdf_mem_alloc_consistent(qdf_dev,
444 				qdf_dev->dev,
445 				(fst->max_entries * HAL_RX_FST_ENTRY_SIZE),
446 				&fst->base_paddr);
447 
448 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
449 		  "hal_rx_fst base address 0x%pK", (void *)fst->base_paddr);
450 	if (!fst->base_vaddr) {
451 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
452 			  FL("hal fst->base_vaddr allocation failed"));
453 		qdf_mem_free(fst);
454 		return NULL;
455 	}
456 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_DEBUG,
457 			   (void *)fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
458 
459 	qdf_mem_set((uint8_t *)fst->base_vaddr,
460 		    (fst->max_entries * HAL_RX_FST_ENTRY_SIZE), 0);
461 
462 	hal_rx_fst_key_configure(fst);
463 	hal_flow_toeplitz_create_cache(fst);
464 	*hal_fst_base_paddr = (uint64_t)fst->base_paddr;
465 	return fst;
466 }
467 qdf_export_symbol(hal_rx_fst_attach);
468 
469 /**
470  * hal_rx_fst_detach() - De-init the Rx flow search table from HW
471  *
472  * @rx_fst: Pointer to the Rx FST
473  * @qdf_dev: QDF device handle
474  *
475  * Return:
476  */
477 void hal_rx_fst_detach(struct hal_rx_fst *rx_fst,
478 		       qdf_device_t qdf_dev)
479 {
480 	if (!rx_fst || !qdf_dev)
481 		return;
482 
483 	qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
484 				rx_fst->max_entries * HAL_RX_FST_ENTRY_SIZE,
485 				rx_fst->base_vaddr, rx_fst->base_paddr, 0);
486 
487 	qdf_mem_free(rx_fst);
488 }
489 qdf_export_symbol(hal_rx_fst_detach);
490 
491 #ifndef WLAN_SUPPORT_RX_FISA
492 /**
493  * hal_flow_toeplitz_hash() - Calculate Toeplitz hash by using the cached key
494  *
495  * @hal_fst: FST Handle
496  * @flow: Flow Parameters
497  *
498  * Return: Success/Failure
499  */
500 uint32_t
501 hal_flow_toeplitz_hash(void *hal_fst, struct hal_rx_flow *flow)
502 {
503 	int i, j;
504 	uint32_t hash = 0;
505 	struct hal_rx_fst *fst = (struct hal_rx_fst *)hal_fst;
506 	uint32_t input[HAL_FST_HASH_KEY_SIZE_WORDS];
507 	uint8_t *tuple;
508 
509 	qdf_mem_zero(input, HAL_FST_HASH_KEY_SIZE_BYTES);
510 	*(uint32_t *)&input[0] = qdf_htonl(flow->tuple_info.src_ip_127_96);
511 	*(uint32_t *)&input[1] = qdf_htonl(flow->tuple_info.src_ip_95_64);
512 	*(uint32_t *)&input[2] = qdf_htonl(flow->tuple_info.src_ip_63_32);
513 	*(uint32_t *)&input[3] = qdf_htonl(flow->tuple_info.src_ip_31_0);
514 	*(uint32_t *)&input[4] = qdf_htonl(flow->tuple_info.dest_ip_127_96);
515 	*(uint32_t *)&input[5] = qdf_htonl(flow->tuple_info.dest_ip_95_64);
516 	*(uint32_t *)&input[6] = qdf_htonl(flow->tuple_info.dest_ip_63_32);
517 	*(uint32_t *)&input[7] = qdf_htonl(flow->tuple_info.dest_ip_31_0);
518 	*(uint32_t *)&input[8] = (flow->tuple_info.dest_port << 16) |
519 				 (flow->tuple_info.src_port);
520 	*(uint32_t *)&input[9] = flow->tuple_info.l4_protocol;
521 
522 	tuple = (uint8_t *)input;
523 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
524 			   tuple, sizeof(input));
525 	for (i = 0, j = HAL_FST_HASH_DATA_SIZE - 1;
526 	     i < HAL_FST_HASH_KEY_SIZE_BYTES && j >= 0; i++, j--) {
527 		hash ^= fst->key_cache[i][tuple[j]];
528 	}
529 
530 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_LOW,
531 		  "Hash value %u %u truncated hash %u\n", hash,
532 		  (hash >> 12), (hash >> 12) % (fst->max_entries));
533 
534 	hash >>= 12;
535 	hash &= (fst->max_entries - 1);
536 
537 	return hash;
538 }
539 #else
540 uint32_t
541 hal_flow_toeplitz_hash(void *hal_fst, struct hal_rx_flow *flow)
542 {
543 	return 0;
544 }
545 #endif
546 qdf_export_symbol(hal_flow_toeplitz_hash);
547 
548 /**
549  * hal_rx_get_hal_hash() - Retrieve hash index of a flow in the FST table
550  *
551  * @hal_fst: HAL Rx FST Handle
552  * @flow_hash: Flow hash computed from flow tuple
553  *
554  * Return: hash index truncated to the size of the hash table
555  */
556 uint32_t hal_rx_get_hal_hash(struct hal_rx_fst *hal_fst, uint32_t flow_hash)
557 {
558 	uint32_t trunc_hash = flow_hash;
559 
560 	/* Take care of hash wrap around scenario */
561 	if (flow_hash >= hal_fst->max_entries)
562 		trunc_hash &= hal_fst->hash_mask;
563 	return trunc_hash;
564 }
565 qdf_export_symbol(hal_rx_get_hal_hash);
566 
567 /**
568  * hal_rx_insert_flow_entry() - Add a flow into the FST table
569  *
570  * @hal_fst: HAL Rx FST Handle
571  * @flow_hash: Flow hash computed from flow tuple
572  * @flow_tuple_info: Flow tuple used to compute the hash
573  * @flow_index: Hash index of the flow in the table when inserted successfully
574  *
575  * Return: Success if flow is inserted into the table, error otherwise
576  */
577 QDF_STATUS
578 hal_rx_insert_flow_entry(struct hal_rx_fst *fst, uint32_t flow_hash,
579 			 void *flow_tuple_info, uint32_t *flow_idx)
580 {
581 	int i;
582 	void *hal_fse = NULL;
583 	uint32_t hal_hash = 0;
584 	struct hal_flow_tuple_info hal_tuple_info = { 0 };
585 	QDF_STATUS status;
586 
587 	for (i = 0; i < fst->max_skid_length; i++) {
588 		hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
589 		hal_fse = (uint8_t *)fst->base_vaddr +
590 			(hal_hash * HAL_RX_FST_ENTRY_SIZE);
591 		status = hal_rx_flow_get_tuple_info(hal_fse, &hal_tuple_info);
592 		if (status == QDF_STATUS_E_NOENT)
593 			break;
594 
595 		/* Find the matching flow entry in HW FST */
596 		if (!qdf_mem_cmp(&hal_tuple_info,
597 				 flow_tuple_info,
598 				 sizeof(struct hal_flow_tuple_info))) {
599 			dp_err("Duplicate flow entry in FST %u at skid %u ",
600 			       hal_hash, i);
601 			return QDF_STATUS_E_EXISTS;
602 		}
603 	}
604 	if (i == fst->max_skid_length) {
605 		dp_err("Max skid length reached for hash %u", flow_hash);
606 		return QDF_STATUS_E_RANGE;
607 	}
608 	*flow_idx = hal_hash;
609 	dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
610 		flow_hash, i, hal_fse, *flow_idx);
611 
612 	return QDF_STATUS_SUCCESS;
613 }
614 qdf_export_symbol(hal_rx_insert_flow_entry);
615 
616 /**
617  * hal_rx_find_flow_from_tuple() - Find a flow in the FST table
618  *
619  * @fst: HAL Rx FST Handle
620  * @flow_hash: Flow hash computed from flow tuple
621  * @flow_tuple_info: Flow tuple used to compute the hash
622  * @flow_index: Hash index of the flow in the table when found
623  *
624  * Return: Success if matching flow is found in the table, error otherwise
625  */
626 QDF_STATUS
627 hal_rx_find_flow_from_tuple(struct hal_rx_fst *fst, uint32_t flow_hash,
628 			    void *flow_tuple_info, uint32_t *flow_idx)
629 {
630 	int i;
631 	void *hal_fse = NULL;
632 	uint32_t hal_hash = 0;
633 	struct hal_flow_tuple_info hal_tuple_info = { 0 };
634 	QDF_STATUS status;
635 
636 	for (i = 0; i < fst->max_skid_length; i++) {
637 		hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
638 		hal_fse = (uint8_t *)fst->base_vaddr +
639 			(hal_hash * HAL_RX_FST_ENTRY_SIZE);
640 		status = hal_rx_flow_get_tuple_info(hal_fse, &hal_tuple_info);
641 		if (status != QDF_STATUS_SUCCESS)
642 			continue;
643 
644 		/* Find the matching flow entry in HW FST */
645 		if (!qdf_mem_cmp(&hal_tuple_info,
646 				 flow_tuple_info,
647 				 sizeof(struct hal_flow_tuple_info))) {
648 			break;
649 		}
650 	}
651 
652 	if (i == fst->max_skid_length) {
653 		dp_err("Max skid length reached for hash %u", flow_hash);
654 		return QDF_STATUS_E_RANGE;
655 	}
656 
657 	*flow_idx = hal_hash;
658 	dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
659 		flow_hash, i, hal_fse, *flow_idx);
660 
661 	return QDF_STATUS_SUCCESS;
662 }
663 qdf_export_symbol(hal_rx_find_flow_from_tuple);
664