xref: /wlan-dirver/qca-wifi-host-cmn/hal/wifi3.0/hal_rx_flow.h (revision 503663c6daafffe652fa360bde17243568cd6d2a)
1 /*
2  * Copyright (c) 2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 #ifndef __HAL_RX_FLOW_H
19 #define __HAL_RX_FLOW_H
20 
21 #include "hal_flow.h"
22 #include "wlan_cfg.h"
23 #include "hal_api.h"
24 #include "qdf_mem.h"
25 #include "rx_flow_search_entry.h"
26 
27 #define HAL_FST_HASH_KEY_SIZE_BITS 315
28 #define HAL_FST_HASH_KEY_SIZE_BYTES 40
29 #define HAL_FST_HASH_KEY_SIZE_WORDS 10
30 #define HAL_FST_HASH_DATA_SIZE 37
31 #define HAL_FST_HASH_MASK 0x7ffff
32 #define HAL_RX_FST_ENTRY_SIZE (NUM_OF_DWORDS_RX_FLOW_SEARCH_ENTRY * 4)
33 
34 /**
35  * Four possible options for IP SA/DA prefix, currently use 0x0 which
36  * maps to type 2 in HW spec
37  */
38 #define HAL_FST_IP_DA_SA_PFX_TYPE_IPV4_COMPATIBLE_IPV6 2
39 
40 #define HAL_IP_DA_SA_PREFIX_IPV4_COMPATIBLE_IPV6 0x0
41 
42 /**
43  * REO destination indication is a lower 4-bits of hash value
44  * This should match the REO destination used in Rx hash based routing.
45  */
46 #define HAL_REO_DEST_IND_HASH_MASK	0xF
47 
48 /**
49  * REO destinations are valid from 16-31 for Hawkeye
50  * and 0-15 are not setup for SW
51  */
52 #define HAL_REO_DEST_IND_START_OFFSET 0x10
53 
54 /**
55  * struct hal_rx_flow - Rx Flow parameters to be sent to HW
56  * @tuple_info: Rx Flow 5-tuple (src & dest IP, src & dest ports, L4 protocol)
57  * @reo_destination_handler: REO destination for this flow
58  * @reo_destination_indication: REO indication for this flow
59  * @fse_metadata: Flow metadata or tag passed to HW for marking packets
60  */
61 struct hal_rx_flow {
62 	struct hal_flow_tuple_info tuple_info;
63 	uint8_t reo_destination_handler;
64 	uint8_t reo_destination_indication;
65 	uint32_t fse_metadata;
66 };
67 
68 /**
69  * enum hal_rx_fse_reo_destination_handler
70  * @HAL_RX_FSE_REO_DEST_FT: Use this entry's destination indication
71  * @HAL_RX_FSE_REO_DEST_ASPT: Use Address Search + Peer Table's entry
72  * @HAL_RX_FSE_REO_DEST_FT2: Use FT2's destination indication
73  * @HAL_RX_FSE_REO_DEST_CCE: Use CCE's destination indication for this entry
74  */
75 enum hal_rx_fse_reo_destination_handler {
76 	HAL_RX_FSE_REO_DEST_FT = 0,
77 	HAL_RX_FSE_REO_DEST_ASPT = 1,
78 	HAL_RX_FSE_REO_DEST_FT2 = 2,
79 	HAL_RX_FSE_REO_DEST_CCE = 3,
80 };
81 
82 /**
83  * struct hal_rx_fst - HAL RX Flow search table context
84  * @base_vaddr: Virtual Base address of HW FST
85  * @base_paddr: Physical Base address of HW FST
86  * @key: Pointer to 320-bit Key read from cfg
87  * @shifted_key: Pointer to left-shifted 320-bit Key used for Toeplitz Hash
88  * @max_entries : Max number of entries in flow searchh  table
89  * @max_skid_length : Max search length if there is hash collision
90  * @hash_mask: Hash mask to apply to index into FST
91  * @key_cache: Toepliz Key Cache configured key
92  */
93 struct hal_rx_fst {
94 	uint8_t *base_vaddr;
95 	qdf_dma_addr_t base_paddr;
96 	uint8_t *key;
97 	uint8_t  shifted_key[HAL_FST_HASH_KEY_SIZE_BYTES];
98 	uint16_t max_entries;
99 	uint16_t max_skid_length;
100 	uint16_t hash_mask;
101 	uint32_t key_cache[HAL_FST_HASH_KEY_SIZE_BYTES][1 << 8];
102 };
103 
104 /**
105  * hal_rx_flow_setup_fse() - Setup a flow search entry in HW FST
106  * @fst: Pointer to the Rx Flow Search Table
107  * @table_offset: offset into the table where the flow is to be setup
108  * @flow: Flow Parameters
109  *
110  * Return: Success/Failure
111  */
112 static void *
113 hal_rx_flow_setup_fse(struct hal_rx_fst *fst, uint32_t table_offset,
114 		      struct hal_rx_flow *flow)
115 {
116 	uint8_t *fse;
117 	bool fse_valid;
118 
119 	if (table_offset >= fst->max_entries) {
120 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
121 			  "HAL FSE table offset %u exceeds max entries %u",
122 			  table_offset, fst->max_entries);
123 		return NULL;
124 	}
125 
126 	fse = (uint8_t *)fst->base_vaddr +
127 			(table_offset * HAL_RX_FST_ENTRY_SIZE);
128 
129 	fse_valid = HAL_GET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
130 
131 	if (fse_valid) {
132 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
133 			  "HAL FSE %pK already valid", fse);
134 		return NULL;
135 	}
136 
137 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96) =
138 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96,
139 			       qdf_htonl(flow->tuple_info.src_ip_127_96));
140 
141 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64) =
142 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64,
143 			       qdf_htonl(flow->tuple_info.src_ip_95_64));
144 
145 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32) =
146 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32,
147 			       qdf_htonl(flow->tuple_info.src_ip_63_32));
148 
149 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0) =
150 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0,
151 			       qdf_htonl(flow->tuple_info.src_ip_31_0));
152 
153 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96) =
154 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96,
155 			       qdf_htonl(flow->tuple_info.dest_ip_127_96));
156 
157 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64) =
158 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64,
159 			       qdf_htonl(flow->tuple_info.dest_ip_95_64));
160 
161 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32) =
162 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32,
163 			       qdf_htonl(flow->tuple_info.dest_ip_63_32));
164 
165 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0) =
166 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0,
167 			       qdf_htonl(flow->tuple_info.dest_ip_31_0));
168 
169 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, DEST_PORT);
170 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, DEST_PORT) |=
171 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_8, DEST_PORT,
172 			       (flow->tuple_info.dest_port));
173 
174 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, SRC_PORT);
175 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, SRC_PORT) |=
176 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_8, SRC_PORT,
177 			       (flow->tuple_info.src_port));
178 
179 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL);
180 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL) |=
181 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL,
182 			       flow->tuple_info.l4_protocol);
183 
184 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER);
185 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER) |=
186 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER,
187 			       flow->reo_destination_handler);
188 
189 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
190 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID) |=
191 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, VALID, 1);
192 
193 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_10, METADATA);
194 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_10, METADATA) =
195 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_10, METADATA,
196 			       flow->fse_metadata);
197 
198 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, REO_DESTINATION_INDICATION);
199 	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, REO_DESTINATION_INDICATION) |=
200 		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_11,
201 			       REO_DESTINATION_INDICATION,
202 			       flow->reo_destination_indication);
203 
204 	/* Reset all the other fields in FSE */
205 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, RESERVED_9);
206 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, MSDU_DROP);
207 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, RESERVED_11);
208 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, MSDU_COUNT);
209 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_12, MSDU_BYTE_COUNT);
210 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_13, TIMESTAMP);
211 
212 	return fse;
213 }
214 
215 /**
216  * hal_rx_flow_delete_entry() - Delete a flow from the Rx Flow Search Table
217  * @fst: Pointer to the Rx Flow Search Table
218  * @hal_rx_fse: Pointer to the Rx Flow that is to be deleted from the FST
219  *
220  * Return: Success/Failure
221  */
222 static inline QDF_STATUS
223 hal_rx_flow_delete_entry(struct hal_rx_fst *fst, void *hal_rx_fse)
224 {
225 	uint8_t *fse = (uint8_t *)hal_rx_fse;
226 
227 	if (!HAL_GET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID))
228 		return QDF_STATUS_E_NOENT;
229 
230 	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
231 
232 	return QDF_STATUS_SUCCESS;
233 }
234 
235 /**
236  * hal_rx_fst_key_configure() - Configure the Toeplitz key in the FST
237  * @fst: Pointer to the Rx Flow Search Table
238  *
239  * Return: Success/Failure
240  */
241 static void hal_rx_fst_key_configure(struct hal_rx_fst *fst)
242 {
243 	uint8_t key_bytes[HAL_FST_HASH_KEY_SIZE_BYTES];
244 
245 	qdf_mem_copy(key_bytes, fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
246 
247 	/**
248 	 * The Toeplitz algorithm as per the Microsoft spec works in a
249 	 * “big-endian” manner, using the MSBs of the key to hash the
250 	 * initial bytes of the input going on to use up the lower order bits
251 	 * of the key to hash further bytes of the input until the LSBs of the
252 	 * key are used finally.
253 	 *
254 	 * So first, rightshift 320-bit input key 5 times to get 315 MS bits
255 	 */
256 	key_bitwise_shift_left(key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES, 5);
257 	key_reverse(fst->shifted_key, key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES);
258 }
259 
260 /**
261  * hal_rx_fst_get_base() - Retrieve the virtual base address of the Rx FST
262  * @fst: Pointer to the Rx Flow Search Table
263  *
264  * Return: Success/Failure
265  */
266 static inline void *hal_rx_fst_get_base(struct hal_rx_fst *fst)
267 {
268 	return fst->base_vaddr;
269 }
270 
271 /**
272  * hal_rx_fst_get_fse_size() - Retrieve the size of each entry(flow) in Rx FST
273  *
274  * Return: size of each entry/flow in Rx FST
275  */
276 static inline uint32_t hal_rx_fst_get_fse_size(void)
277 {
278 	return HAL_RX_FST_ENTRY_SIZE;
279 }
280 
281 /**
282  * hal_rx_flow_get_tuple_info() - Retrieve the 5-tuple flow info for an entry
283  * @hal_fse: Pointer to the Flow in Rx FST
284  * @tuple_info: 5-tuple info of the flow returned to the caller
285  *
286  * Return: Success/Failure
287  */
288 QDF_STATUS hal_rx_flow_get_tuple_info(void *hal_fse,
289 				      struct hal_flow_tuple_info *tuple_info)
290 {
291 	if (!hal_fse || !tuple_info)
292 		return QDF_STATUS_E_INVAL;
293 
294 	if (!HAL_GET_FLD(hal_fse, RX_FLOW_SEARCH_ENTRY_9, VALID))
295 		return QDF_STATUS_E_NOENT;
296 
297 	tuple_info->src_ip_127_96 = qdf_ntohl(HAL_GET_FLD(hal_fse,
298 					RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96));
299 	tuple_info->src_ip_95_64 = qdf_ntohl(HAL_GET_FLD(hal_fse,
300 					RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64));
301 	tuple_info->src_ip_63_32 = qdf_ntohl(HAL_GET_FLD(hal_fse,
302 					RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32));
303 	tuple_info->src_ip_31_0 = qdf_ntohl(HAL_GET_FLD(hal_fse,
304 					RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0));
305 	tuple_info->dest_ip_127_96 =
306 		 qdf_ntohl(HAL_GET_FLD(hal_fse,
307 				       RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96));
308 	tuple_info->dest_ip_95_64 = qdf_ntohl(HAL_GET_FLD(hal_fse,
309 					RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64));
310 	tuple_info->dest_ip_63_32 = qdf_ntohl(HAL_GET_FLD(hal_fse,
311 					RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32));
312 	tuple_info->dest_ip_31_0 = qdf_ntohl(HAL_GET_FLD(hal_fse,
313 					RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0));
314 	tuple_info->dest_port = (HAL_GET_FLD(hal_fse,
315 					RX_FLOW_SEARCH_ENTRY_8, DEST_PORT));
316 	tuple_info->src_port = (HAL_GET_FLD(hal_fse,
317 					RX_FLOW_SEARCH_ENTRY_8, SRC_PORT));
318 	tuple_info->l4_protocol = HAL_GET_FLD(hal_fse,
319 					RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL);
320 
321 	return QDF_STATUS_SUCCESS;
322 }
323 
324 /**
325  * hal_flow_toeplitz_create_cache() - Calculate hashes for each possible
326  * byte value with the key taken as is
327  *
328  * @fst: FST Handle
329  * @key: Hash Key
330  *
331  * Return: Success/Failure
332  */
333 void hal_flow_toeplitz_create_cache(struct hal_rx_fst *fst)
334 {
335 	int bit;
336 	int val;
337 	int i;
338 	uint8_t *key = fst->shifted_key;
339 
340 	/*
341 	 * Initialise to first 32 bits of the key; shift in further key material
342 	 * through the loop
343 	 */
344 	uint32_t cur_key = (key[0] << 24) | (key[1] << 16) | (key[2] << 8) |
345 		key[3];
346 
347 	for (i = 0; i < HAL_FST_HASH_KEY_SIZE_BYTES; i++) {
348 		uint8_t new_key_byte;
349 		uint32_t shifted_key[8];
350 
351 		if (i + 4 < HAL_FST_HASH_KEY_SIZE_BYTES)
352 			new_key_byte = key[i + 4];
353 		else
354 			new_key_byte = 0;
355 
356 		shifted_key[0] = cur_key;
357 
358 		for (bit = 1; bit < 8; bit++) {
359 			/*
360 			 * For each iteration, shift out one more bit of the
361 			 * current key and shift in one more bit of the new key
362 			 * material
363 			 */
364 			shifted_key[bit] = cur_key << bit |
365 				new_key_byte >> (8 - bit);
366 		}
367 
368 		for (val = 0; val < (1 << 8); val++) {
369 			uint32_t hash = 0;
370 			int mask;
371 
372 			/*
373 			 * For each bit set in the input, XOR in
374 			 * the appropriately shifted key
375 			 */
376 			for (bit = 0, mask = 1 << 7; bit < 8; bit++, mask >>= 1)
377 				if ((val & mask))
378 					hash ^= shifted_key[bit];
379 
380 			fst->key_cache[i][val] = hash;
381 		}
382 
383 		cur_key = cur_key << 8 | new_key_byte;
384 	}
385 }
386 
387 /**
388  * hal_rx_fst_attach() - Initialize Rx flow search table in HW FST
389  *
390  * @qdf_dev: QDF device handle
391  * @hal_fst_base_paddr: Pointer to the physical base address of the Rx FST
392  * @max_entries: Max number of flows allowed in the FST
393  * @max_search: Number of collisions allowed in the hash-based FST
394  * @hash_key: Toeplitz key used for the hash FST
395  *
396  * Return:
397  */
398 static struct hal_rx_fst *
399 hal_rx_fst_attach(qdf_device_t qdf_dev,
400 		  uint64_t *hal_fst_base_paddr, uint16_t max_entries,
401 		  uint16_t max_search, uint8_t *hash_key)
402 {
403 	struct hal_rx_fst *fst = qdf_mem_malloc(sizeof(struct hal_rx_fst));
404 
405 	if (!fst) {
406 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
407 			  FL("hal fst allocation failed,"));
408 		return NULL;
409 	}
410 
411 	qdf_mem_set(fst, 0, sizeof(struct hal_rx_fst));
412 
413 	fst->key = hash_key;
414 	fst->max_skid_length = max_search;
415 	fst->max_entries = max_entries;
416 	fst->hash_mask = max_entries - 1;
417 
418 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
419 		  "HAL FST allocation %x %d * %d\n", fst,
420 		  fst->max_entries, HAL_RX_FST_ENTRY_SIZE);
421 
422 	fst->base_vaddr = (uint8_t *)qdf_mem_alloc_consistent(qdf_dev,
423 				qdf_dev->dev,
424 				(fst->max_entries * HAL_RX_FST_ENTRY_SIZE),
425 				&fst->base_paddr);
426 
427 	if (!fst->base_vaddr) {
428 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
429 			  FL("hal fst->base_vaddr allocation failed"));
430 		qdf_mem_free(fst);
431 		return NULL;
432 	}
433 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_DEBUG,
434 			   (void *)fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
435 
436 	qdf_mem_set((uint8_t *)fst->base_vaddr, 0,
437 		    (fst->max_entries * HAL_RX_FST_ENTRY_SIZE));
438 
439 	hal_rx_fst_key_configure(fst);
440 	hal_flow_toeplitz_create_cache(fst);
441 	*hal_fst_base_paddr = (uint64_t)fst->base_paddr;
442 	return fst;
443 }
444 
445 /**
446  * hal_rx_fst_detach() - De-init the Rx flow search table from HW
447  *
448  * @rx_fst: Pointer to the Rx FST
449  * @qdf_dev: QDF device handle
450  *
451  * Return:
452  */
453 void hal_rx_fst_detach(struct hal_rx_fst *rx_fst,
454 		       qdf_device_t qdf_dev)
455 {
456 	if (!rx_fst || !qdf_dev)
457 		return;
458 
459 	qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
460 				rx_fst->max_entries * HAL_RX_FST_ENTRY_SIZE,
461 				rx_fst->base_vaddr, rx_fst->base_paddr, 0);
462 
463 	qdf_mem_free(rx_fst);
464 }
465 
466 /**
467  * hal_flow_toeplitz_hash() - Calculate Toeplitz hash by using the cached key
468  *
469  * @hal_fst: FST Handle
470  * @flow: Flow Parameters
471  *
472  * Return: Success/Failure
473  */
474 static inline uint32_t
475 hal_flow_toeplitz_hash(void *hal_fst, struct hal_rx_flow *flow)
476 {
477 	int i, j;
478 	uint32_t hash = 0;
479 	struct hal_rx_fst *fst = (struct hal_rx_fst *)hal_fst;
480 	uint32_t input[HAL_FST_HASH_KEY_SIZE_WORDS];
481 	uint8_t *tuple;
482 
483 	qdf_mem_zero(input, HAL_FST_HASH_KEY_SIZE_BYTES);
484 	*(uint32_t *)&input[0] = qdf_htonl(flow->tuple_info.src_ip_127_96);
485 	*(uint32_t *)&input[1] = qdf_htonl(flow->tuple_info.src_ip_95_64);
486 	*(uint32_t *)&input[2] = qdf_htonl(flow->tuple_info.src_ip_63_32);
487 	*(uint32_t *)&input[3] = qdf_htonl(flow->tuple_info.src_ip_31_0);
488 	*(uint32_t *)&input[4] = qdf_htonl(flow->tuple_info.dest_ip_127_96);
489 	*(uint32_t *)&input[5] = qdf_htonl(flow->tuple_info.dest_ip_95_64);
490 	*(uint32_t *)&input[6] = qdf_htonl(flow->tuple_info.dest_ip_63_32);
491 	*(uint32_t *)&input[7] = qdf_htonl(flow->tuple_info.dest_ip_31_0);
492 	*(uint32_t *)&input[8] = (flow->tuple_info.dest_port << 16) |
493 				 (flow->tuple_info.src_port);
494 	*(uint32_t *)&input[9] = flow->tuple_info.l4_protocol;
495 
496 	tuple = (uint8_t *)input;
497 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
498 			   tuple, sizeof(input));
499 	for (i = 0, j = HAL_FST_HASH_DATA_SIZE - 1;
500 	     i < HAL_FST_HASH_KEY_SIZE_BYTES && j >= 0; i++, j--) {
501 		hash ^= fst->key_cache[i][tuple[j]];
502 	}
503 
504 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_LOW,
505 		  "Hash value %u %u truncated hash %u\n", hash,
506 		  (hash >> 12), (hash >> 12) % (fst->max_entries));
507 
508 	hash >>= 12;
509 	hash &= (fst->max_entries - 1);
510 
511 	return hash;
512 }
513 
514 /**
515  * hal_rx_get_hal_hash() - Retrieve hash index of a flow in the FST table
516  *
517  * @hal_fst: HAL Rx FST Handle
518  * @flow_hash: Flow hash computed from flow tuple
519  *
520  * Return: hash index truncated to the size of the hash table
521  */
522 inline
523 uint32_t hal_rx_get_hal_hash(struct hal_rx_fst *hal_fst, uint32_t flow_hash)
524 {
525 	uint32_t trunc_hash = flow_hash;
526 
527 	/* Take care of hash wrap around scenario */
528 	if (flow_hash >= hal_fst->max_entries)
529 		trunc_hash &= hal_fst->hash_mask;
530 	return trunc_hash;
531 }
532 
533 /**
534  * hal_rx_insert_flow_entry() - Add a flow into the FST table
535  *
536  * @hal_fst: HAL Rx FST Handle
537  * @flow_hash: Flow hash computed from flow tuple
538  * @flow_tuple_info: Flow tuple used to compute the hash
539  * @flow_index: Hash index of the flow in the table when inserted successfully
540  *
541  * Return: Success if flow is inserted into the table, error otherwise
542  */
543 QDF_STATUS
544 hal_rx_insert_flow_entry(struct hal_rx_fst *fst, uint32_t flow_hash,
545 			 void *flow_tuple_info, uint32_t *flow_idx) {
546 	int i;
547 	void *hal_fse;
548 	uint32_t hal_hash;
549 	struct hal_flow_tuple_info hal_tuple_info = { 0 };
550 	QDF_STATUS status;
551 
552 	for (i = 0; i < fst->max_skid_length; i++) {
553 		hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
554 		hal_fse = (uint8_t *)fst->base_vaddr +
555 			(hal_hash * HAL_RX_FST_ENTRY_SIZE);
556 		status = hal_rx_flow_get_tuple_info(hal_fse, &hal_tuple_info);
557 		if (QDF_STATUS_E_NOENT == status)
558 			break;
559 
560 		/* Find the matching flow entry in HW FST */
561 		if (!qdf_mem_cmp(&hal_tuple_info,
562 				 flow_tuple_info,
563 				 sizeof(struct hal_flow_tuple_info))) {
564 			dp_err("Duplicate flow entry in FST %u at skid %u ",
565 			       hal_hash, i);
566 			return QDF_STATUS_E_EXISTS;
567 		}
568 	}
569 	if (i == fst->max_skid_length) {
570 		dp_err("Max skid length reached for hash %u", flow_hash);
571 		return QDF_STATUS_E_RANGE;
572 	}
573 	*flow_idx = hal_hash;
574 	dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
575 		flow_hash, i, hal_fse, *flow_idx);
576 
577 	return QDF_STATUS_SUCCESS;
578 }
579 
580 /**
581  * hal_rx_find_flow_from_tuple() - Find a flow in the FST table
582  *
583  * @fst: HAL Rx FST Handle
584  * @flow_hash: Flow hash computed from flow tuple
585  * @flow_tuple_info: Flow tuple used to compute the hash
586  * @flow_index: Hash index of the flow in the table when found
587  *
588  * Return: Success if matching flow is found in the table, error otherwise
589  */
590 QDF_STATUS
591 hal_rx_find_flow_from_tuple(struct hal_rx_fst *fst, uint32_t flow_hash,
592 			    void *flow_tuple_info, uint32_t *flow_idx)
593 {
594 	int i;
595 	void *hal_fse;
596 	uint32_t hal_hash;
597 	struct hal_flow_tuple_info hal_tuple_info = { 0 };
598 	QDF_STATUS status;
599 
600 	for (i = 0; i < fst->max_skid_length; i++) {
601 		hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
602 		hal_fse = (uint8_t *)fst->base_vaddr +
603 			(hal_hash * HAL_RX_FST_ENTRY_SIZE);
604 		status = hal_rx_flow_get_tuple_info(hal_fse, &hal_tuple_info);
605 		if (QDF_STATUS_SUCCESS != status)
606 			continue;
607 
608 		/* Find the matching flow entry in HW FST */
609 		if (!qdf_mem_cmp(&hal_tuple_info,
610 				 flow_tuple_info,
611 				 sizeof(struct hal_flow_tuple_info))) {
612 			break;
613 		}
614 	}
615 
616 	if (i == fst->max_skid_length) {
617 		dp_err("Max skid length reached for hash %u", flow_hash);
618 		return QDF_STATUS_E_RANGE;
619 	}
620 
621 	*flow_idx = hal_hash;
622 	dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
623 		flow_hash, i, hal_fse, *flow_idx);
624 
625 	return QDF_STATUS_SUCCESS;
626 }
627 
628 #endif /* HAL_RX_FLOW_H */
629