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