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