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