hal_rx_flow.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. #include "qdf_module.h"
  18. #include "dp_types.h"
  19. #include "hal_rx_flow.h"
  20. #include "qdf_ssr_driver_dump.h"
  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: reference where FSE will be copied
  26. * @len: length of FSE
  27. *
  28. * Return: If read is successful 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. if (hal_soc->ops->hal_rx_flow_get_cmem_fse) {
  36. return hal_soc->ops->hal_rx_flow_get_cmem_fse(
  37. hal_soc, fse_offset, fse, len);
  38. }
  39. }
  40. #if defined(WLAN_SUPPORT_RX_FISA)
  41. static inline void hal_rx_dump_fse(struct rx_flow_search_entry *fse, int index)
  42. {
  43. dp_info("index %d:"
  44. " src_ip_127_96 0x%x"
  45. " src_ip_95_640 0x%x"
  46. " src_ip_63_32 0x%x"
  47. " src_ip_31_0 0x%x"
  48. " dest_ip_127_96 0x%x"
  49. " dest_ip_95_64 0x%x"
  50. " dest_ip_63_32 0x%x"
  51. " dest_ip_31_0 0x%x"
  52. " src_port 0x%x"
  53. " dest_port 0x%x"
  54. " l4_protocol 0x%x"
  55. " valid 0x%x"
  56. " reo_destination_indication 0x%x"
  57. " msdu_drop 0x%x"
  58. " reo_destination_handler 0x%x"
  59. " metadata 0x%x"
  60. " aggregation_count0x%x"
  61. " lro_eligible 0x%x"
  62. " msdu_count 0x%x"
  63. " msdu_byte_count 0x%x"
  64. " timestamp 0x%x"
  65. " cumulative_l4_checksum 0x%x"
  66. " cumulative_ip_length 0x%x"
  67. " tcp_sequence_number 0x%x",
  68. index,
  69. fse->src_ip_127_96,
  70. fse->src_ip_95_64,
  71. fse->src_ip_63_32,
  72. fse->src_ip_31_0,
  73. fse->dest_ip_127_96,
  74. fse->dest_ip_95_64,
  75. fse->dest_ip_63_32,
  76. fse->dest_ip_31_0,
  77. fse->src_port,
  78. fse->dest_port,
  79. fse->l4_protocol,
  80. fse->valid,
  81. fse->reo_destination_indication,
  82. fse->msdu_drop,
  83. fse->reo_destination_handler,
  84. fse->metadata,
  85. fse->aggregation_count,
  86. fse->lro_eligible,
  87. fse->msdu_count,
  88. fse->msdu_byte_count,
  89. fse->timestamp,
  90. #ifdef QCA_WIFI_KIWI_V2
  91. fse->cumulative_ip_length_pmac1,
  92. #else
  93. fse->cumulative_l4_checksum,
  94. #endif
  95. fse->cumulative_ip_length,
  96. fse->tcp_sequence_number);
  97. }
  98. void hal_rx_dump_fse_table(struct hal_rx_fst *fst)
  99. {
  100. int i = 0;
  101. struct rx_flow_search_entry *fse =
  102. (struct rx_flow_search_entry *)fst->base_vaddr;
  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. void hal_rx_dump_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t fse_offset,
  110. int index)
  111. {
  112. struct rx_flow_search_entry fse = {0};
  113. if (!fse_offset)
  114. return;
  115. hal_rx_flow_get_cmem_fse(hal_soc_hdl, fse_offset, (uint32_t *)&fse,
  116. sizeof(struct rx_flow_search_entry));
  117. if (fse.valid)
  118. hal_rx_dump_fse(&fse, index);
  119. }
  120. #else
  121. void hal_rx_dump_fse_table(struct hal_rx_fst *fst)
  122. {
  123. }
  124. void hal_rx_dump_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t fse_offset,
  125. int index)
  126. {
  127. }
  128. #endif
  129. void *
  130. hal_rx_flow_setup_fse(hal_soc_handle_t hal_soc_hdl,
  131. struct hal_rx_fst *fst, uint32_t table_offset,
  132. struct hal_rx_flow *flow)
  133. {
  134. struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
  135. if (hal_soc->ops->hal_rx_flow_setup_fse) {
  136. return hal_soc->ops->hal_rx_flow_setup_fse((uint8_t *)fst,
  137. table_offset,
  138. (uint8_t *)flow);
  139. }
  140. return NULL;
  141. }
  142. qdf_export_symbol(hal_rx_flow_setup_fse);
  143. uint32_t
  144. hal_rx_flow_setup_cmem_fse(hal_soc_handle_t hal_soc_hdl, uint32_t cmem_ba,
  145. uint32_t table_offset, struct hal_rx_flow *flow)
  146. {
  147. struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
  148. if (hal_soc->ops->hal_rx_flow_setup_cmem_fse) {
  149. return hal_soc->ops->hal_rx_flow_setup_cmem_fse(
  150. hal_soc, cmem_ba,
  151. table_offset, (uint8_t *)flow);
  152. }
  153. return 0;
  154. }
  155. qdf_export_symbol(hal_rx_flow_setup_cmem_fse);
  156. uint32_t hal_rx_flow_get_cmem_fse_timestamp(hal_soc_handle_t hal_soc_hdl,
  157. uint32_t fse_offset)
  158. {
  159. struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
  160. if (hal_soc->ops->hal_rx_flow_get_cmem_fse_ts) {
  161. return hal_soc->ops->hal_rx_flow_get_cmem_fse_ts(hal_soc,
  162. fse_offset);
  163. }
  164. return 0;
  165. }
  166. qdf_export_symbol(hal_rx_flow_get_cmem_fse_timestamp);
  167. QDF_STATUS
  168. hal_rx_flow_delete_entry(hal_soc_handle_t hal_soc_hdl,
  169. struct hal_rx_fst *fst, void *hal_rx_fse)
  170. {
  171. struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
  172. if (hal_soc->ops->hal_rx_flow_delete_entry) {
  173. return hal_soc->ops->hal_rx_flow_delete_entry((uint8_t *)fst,
  174. hal_rx_fse);
  175. }
  176. return QDF_STATUS_E_NOSUPPORT;
  177. }
  178. qdf_export_symbol(hal_rx_flow_delete_entry);
  179. #ifndef WLAN_SUPPORT_RX_FISA
  180. /**
  181. * hal_rx_fst_key_configure() - Configure the Toeplitz key in the FST
  182. * @fst: Pointer to the Rx Flow Search Table
  183. *
  184. * Return: Success/Failure
  185. */
  186. static void hal_rx_fst_key_configure(struct hal_rx_fst *fst)
  187. {
  188. uint8_t key_bytes[HAL_FST_HASH_KEY_SIZE_BYTES];
  189. qdf_mem_copy(key_bytes, fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
  190. /*
  191. * The Toeplitz algorithm as per the Microsoft spec works in a
  192. * “big-endian” manner, using the MSBs of the key to hash the
  193. * initial bytes of the input going on to use up the lower order bits
  194. * of the key to hash further bytes of the input until the LSBs of the
  195. * key are used finally.
  196. *
  197. * So first, rightshift 320-bit input key 5 times to get 315 MS bits
  198. */
  199. key_bitwise_shift_left(key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES, 5);
  200. key_reverse(fst->shifted_key, key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES);
  201. }
  202. #else
  203. static void hal_rx_fst_key_configure(struct hal_rx_fst *fst)
  204. {
  205. }
  206. #endif
  207. /**
  208. * hal_rx_fst_get_base() - Retrieve the virtual base address of the Rx FST
  209. * @fst: Pointer to the Rx Flow Search Table
  210. *
  211. * Return: Success/Failure
  212. */
  213. static inline void *hal_rx_fst_get_base(struct hal_rx_fst *fst)
  214. {
  215. return fst->base_vaddr;
  216. }
  217. /**
  218. * hal_rx_fst_get_fse_size() - Retrieve the size of each entry(flow) in Rx FST
  219. * @hal_soc_hdl: HAL SOC handle
  220. *
  221. * Return: size of each entry/flow in Rx FST
  222. */
  223. static inline uint32_t
  224. hal_rx_fst_get_fse_size(hal_soc_handle_t hal_soc_hdl)
  225. {
  226. struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
  227. if (hal_soc->ops->hal_rx_fst_get_fse_size)
  228. return hal_soc->ops->hal_rx_fst_get_fse_size();
  229. return 0;
  230. }
  231. /**
  232. * hal_rx_flow_get_tuple_info() - Get a flow search entry in HW FST
  233. * @hal_soc_hdl: HAL SOC handle
  234. * @fst: Pointer to the Rx Flow Search Table
  235. * @hal_hash: HAL 5 tuple hash
  236. * @tuple_info: 5-tuple info of the flow returned to the caller
  237. *
  238. * Return: Success/Failure
  239. */
  240. void *
  241. hal_rx_flow_get_tuple_info(hal_soc_handle_t hal_soc_hdl,
  242. struct hal_rx_fst *fst,
  243. uint32_t hal_hash,
  244. struct hal_flow_tuple_info *tuple_info)
  245. {
  246. struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
  247. if (hal_soc->ops->hal_rx_flow_get_tuple_info)
  248. return hal_soc->ops->hal_rx_flow_get_tuple_info(
  249. (uint8_t *)fst,
  250. hal_hash,
  251. (uint8_t *)tuple_info);
  252. return NULL;
  253. }
  254. #ifndef WLAN_SUPPORT_RX_FISA
  255. /**
  256. * hal_flow_toeplitz_create_cache() - Calculate hashes for each possible
  257. * byte value with the key taken as is
  258. * @fst: FST Handle
  259. *
  260. * Return: None
  261. */
  262. static void hal_flow_toeplitz_create_cache(struct hal_rx_fst *fst)
  263. {
  264. int bit;
  265. int val;
  266. int i;
  267. uint8_t *key = fst->shifted_key;
  268. /*
  269. * Initialise to first 32 bits of the key; shift in further key material
  270. * through the loop
  271. */
  272. uint32_t cur_key = (key[0] << 24) | (key[1] << 16) | (key[2] << 8) |
  273. key[3];
  274. for (i = 0; i < HAL_FST_HASH_KEY_SIZE_BYTES; i++) {
  275. uint8_t new_key_byte;
  276. uint32_t shifted_key[8];
  277. if (i + 4 < HAL_FST_HASH_KEY_SIZE_BYTES)
  278. new_key_byte = key[i + 4];
  279. else
  280. new_key_byte = 0;
  281. shifted_key[0] = cur_key;
  282. for (bit = 1; bit < 8; bit++) {
  283. /*
  284. * For each iteration, shift out one more bit of the
  285. * current key and shift in one more bit of the new key
  286. * material
  287. */
  288. shifted_key[bit] = cur_key << bit |
  289. new_key_byte >> (8 - bit);
  290. }
  291. for (val = 0; val < (1 << 8); val++) {
  292. uint32_t hash = 0;
  293. int mask;
  294. /*
  295. * For each bit set in the input, XOR in
  296. * the appropriately shifted key
  297. */
  298. for (bit = 0, mask = 1 << 7; bit < 8; bit++, mask >>= 1)
  299. if ((val & mask))
  300. hash ^= shifted_key[bit];
  301. fst->key_cache[i][val] = hash;
  302. }
  303. cur_key = cur_key << 8 | new_key_byte;
  304. }
  305. }
  306. #else
  307. static void hal_flow_toeplitz_create_cache(struct hal_rx_fst *fst)
  308. {
  309. }
  310. #endif
  311. struct hal_rx_fst *
  312. hal_rx_fst_attach(hal_soc_handle_t hal_soc_hdl,
  313. qdf_device_t qdf_dev,
  314. uint64_t *hal_fst_base_paddr, uint16_t max_entries,
  315. uint16_t max_search, uint8_t *hash_key,
  316. uint64_t fst_cmem_base)
  317. {
  318. struct hal_rx_fst *fst = qdf_mem_malloc(sizeof(struct hal_rx_fst));
  319. uint32_t fst_entry_size;
  320. if (!fst) {
  321. QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
  322. FL("hal fst allocation failed"));
  323. return NULL;
  324. }
  325. qdf_mem_set(fst, sizeof(struct hal_rx_fst), 0);
  326. fst->key = hash_key;
  327. fst->max_skid_length = max_search;
  328. fst->max_entries = max_entries;
  329. fst->hash_mask = max_entries - 1;
  330. fst_entry_size = hal_rx_fst_get_fse_size(hal_soc_hdl);
  331. fst->fst_entry_size = fst_entry_size;
  332. QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
  333. "HAL FST allocation %pK %d * %d\n", fst,
  334. fst->max_entries, fst_entry_size);
  335. qdf_ssr_driver_dump_register_region("hal_rx_fst", fst, sizeof(*fst));
  336. if (fst_cmem_base == 0) {
  337. /* FST is in DDR */
  338. fst->base_vaddr = (uint8_t *)qdf_mem_alloc_consistent(qdf_dev,
  339. qdf_dev->dev,
  340. (fst->max_entries * fst_entry_size),
  341. &fst->base_paddr);
  342. if (!fst->base_vaddr) {
  343. QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
  344. FL("hal fst->base_vaddr allocation failed"));
  345. qdf_mem_free(fst);
  346. return NULL;
  347. }
  348. qdf_ssr_driver_dump_register_region("dp_fisa_hw_fse_table",
  349. fst->base_vaddr,
  350. (fst->max_entries *
  351. fst_entry_size));
  352. *hal_fst_base_paddr = (uint64_t)fst->base_paddr;
  353. } else {
  354. *hal_fst_base_paddr = fst_cmem_base;
  355. goto out;
  356. }
  357. QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
  358. "hal_rx_fst base address 0x%pK", (void *)fst->base_paddr);
  359. QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_DEBUG,
  360. (void *)fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
  361. qdf_mem_set((uint8_t *)fst->base_vaddr,
  362. (fst->max_entries * fst_entry_size), 0);
  363. out:
  364. hal_rx_fst_key_configure(fst);
  365. hal_flow_toeplitz_create_cache(fst);
  366. return fst;
  367. }
  368. qdf_export_symbol(hal_rx_fst_attach);
  369. void hal_rx_fst_detach(hal_soc_handle_t hal_soc_hdl, struct hal_rx_fst *rx_fst,
  370. qdf_device_t qdf_dev, uint64_t fst_cmem_base)
  371. {
  372. if (!rx_fst || !qdf_dev)
  373. return;
  374. qdf_ssr_driver_dump_unregister_region("hal_rx_fst");
  375. if (fst_cmem_base == 0 && rx_fst->base_vaddr) {
  376. qdf_ssr_driver_dump_unregister_region("dp_fisa_hw_fse_table");
  377. qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
  378. rx_fst->max_entries *
  379. rx_fst->fst_entry_size,
  380. rx_fst->base_vaddr, rx_fst->base_paddr,
  381. 0);
  382. }
  383. qdf_mem_free(rx_fst);
  384. }
  385. qdf_export_symbol(hal_rx_fst_detach);
  386. #ifndef WLAN_SUPPORT_RX_FISA
  387. uint32_t
  388. hal_flow_toeplitz_hash(void *hal_fst, struct hal_rx_flow *flow)
  389. {
  390. int i, j;
  391. uint32_t hash = 0;
  392. struct hal_rx_fst *fst = (struct hal_rx_fst *)hal_fst;
  393. uint32_t input[HAL_FST_HASH_KEY_SIZE_WORDS];
  394. uint8_t *tuple;
  395. qdf_mem_zero(input, HAL_FST_HASH_KEY_SIZE_BYTES);
  396. *(uint32_t *)&input[0] = qdf_htonl(flow->tuple_info.src_ip_127_96);
  397. *(uint32_t *)&input[1] = qdf_htonl(flow->tuple_info.src_ip_95_64);
  398. *(uint32_t *)&input[2] = qdf_htonl(flow->tuple_info.src_ip_63_32);
  399. *(uint32_t *)&input[3] = qdf_htonl(flow->tuple_info.src_ip_31_0);
  400. *(uint32_t *)&input[4] = qdf_htonl(flow->tuple_info.dest_ip_127_96);
  401. *(uint32_t *)&input[5] = qdf_htonl(flow->tuple_info.dest_ip_95_64);
  402. *(uint32_t *)&input[6] = qdf_htonl(flow->tuple_info.dest_ip_63_32);
  403. *(uint32_t *)&input[7] = qdf_htonl(flow->tuple_info.dest_ip_31_0);
  404. *(uint32_t *)&input[8] = (flow->tuple_info.dest_port << 16) |
  405. (flow->tuple_info.src_port);
  406. *(uint32_t *)&input[9] = flow->tuple_info.l4_protocol;
  407. tuple = (uint8_t *)input;
  408. QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
  409. tuple, sizeof(input));
  410. for (i = 0, j = HAL_FST_HASH_DATA_SIZE - 1;
  411. i < HAL_FST_HASH_KEY_SIZE_BYTES && j >= 0; i++, j--) {
  412. hash ^= fst->key_cache[i][tuple[j]];
  413. }
  414. QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_LOW,
  415. "Hash value %u %u truncated hash %u\n", hash,
  416. (hash >> 12), (hash >> 12) % (fst->max_entries));
  417. hash >>= 12;
  418. hash &= (fst->max_entries - 1);
  419. return hash;
  420. }
  421. #else
  422. uint32_t
  423. hal_flow_toeplitz_hash(void *hal_fst, struct hal_rx_flow *flow)
  424. {
  425. return 0;
  426. }
  427. #endif
  428. qdf_export_symbol(hal_flow_toeplitz_hash);
  429. uint32_t hal_rx_get_hal_hash(struct hal_rx_fst *hal_fst, uint32_t flow_hash)
  430. {
  431. uint32_t trunc_hash = flow_hash;
  432. /* Take care of hash wrap around scenario */
  433. if (flow_hash >= hal_fst->max_entries)
  434. trunc_hash &= hal_fst->hash_mask;
  435. return trunc_hash;
  436. }
  437. qdf_export_symbol(hal_rx_get_hal_hash);
  438. QDF_STATUS
  439. hal_rx_insert_flow_entry(hal_soc_handle_t hal_soc,
  440. struct hal_rx_fst *fst, uint32_t flow_hash,
  441. void *flow_tuple_info, uint32_t *flow_idx)
  442. {
  443. int i;
  444. void *hal_fse = NULL;
  445. uint32_t hal_hash = 0;
  446. struct hal_flow_tuple_info hal_tuple_info = { 0 };
  447. for (i = 0; i < fst->max_skid_length; i++) {
  448. hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
  449. hal_fse = hal_rx_flow_get_tuple_info(hal_soc, fst, hal_hash,
  450. &hal_tuple_info);
  451. if (!hal_fse)
  452. break;
  453. /* Find the matching flow entry in HW FST */
  454. if (!qdf_mem_cmp(&hal_tuple_info,
  455. flow_tuple_info,
  456. sizeof(struct hal_flow_tuple_info))) {
  457. dp_err("Duplicate flow entry in FST %u at skid %u ",
  458. hal_hash, i);
  459. return QDF_STATUS_E_EXISTS;
  460. }
  461. }
  462. if (i == fst->max_skid_length) {
  463. dp_err("Max skid length reached for hash %u", flow_hash);
  464. return QDF_STATUS_E_RANGE;
  465. }
  466. *flow_idx = hal_hash;
  467. dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
  468. flow_hash, i, hal_fse, *flow_idx);
  469. return QDF_STATUS_SUCCESS;
  470. }
  471. qdf_export_symbol(hal_rx_insert_flow_entry);
  472. QDF_STATUS
  473. hal_rx_find_flow_from_tuple(hal_soc_handle_t hal_soc_hdl,
  474. struct hal_rx_fst *fst, uint32_t flow_hash,
  475. void *flow_tuple_info, uint32_t *flow_idx)
  476. {
  477. int i;
  478. void *hal_fse = NULL;
  479. uint32_t hal_hash = 0;
  480. struct hal_flow_tuple_info hal_tuple_info = { 0 };
  481. for (i = 0; i < fst->max_skid_length; i++) {
  482. hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
  483. hal_fse = hal_rx_flow_get_tuple_info(hal_soc_hdl, fst, hal_hash,
  484. &hal_tuple_info);
  485. if (!hal_fse)
  486. continue;
  487. /* Find the matching flow entry in HW FST */
  488. if (!qdf_mem_cmp(&hal_tuple_info,
  489. flow_tuple_info,
  490. sizeof(struct hal_flow_tuple_info))) {
  491. break;
  492. }
  493. }
  494. if (i == fst->max_skid_length) {
  495. dp_err("Max skid length reached for hash %u", flow_hash);
  496. return QDF_STATUS_E_RANGE;
  497. }
  498. *flow_idx = hal_hash;
  499. dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
  500. flow_hash, i, hal_fse, *flow_idx);
  501. return QDF_STATUS_SUCCESS;
  502. }
  503. qdf_export_symbol(hal_rx_find_flow_from_tuple);