blob: 353f9e6f7d6b01ac19658b55fc9406fe3b318abf [file] [log] [blame]
Sumeet Raoc4fa4df2019-07-05 02:11:19 -07001/*
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 */
61struct 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 */
75enum 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 */
93struct 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 */
112static void *
113hal_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 */
222static inline QDF_STATUS
223hal_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 */
241static 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 */
266static 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 */
276static 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 */
288QDF_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 */
333void 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 */
398static struct hal_rx_fst *
399hal_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 */
453void 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 */
474static inline uint32_t
475hal_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 */
522inline
523uint32_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 */
543QDF_STATUS
544hal_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 */
590QDF_STATUS
591hal_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 */