dp_flow.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  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. #ifdef WLAN_SUPPORT_RX_FLOW_TAG
  19. #include "dp_types.h"
  20. #include "qdf_mem.h"
  21. #include "qdf_nbuf.h"
  22. #include "cfg_dp.h"
  23. #include "wlan_cfg.h"
  24. #include "dp_types.h"
  25. #include "hal_rx_flow.h"
  26. #include "dp_htt.h"
  27. /**
  28. * In Hawkeye, a hardware bug disallows SW to only clear a single flow entry
  29. * when added/deleted by upper layer. Workaround is to clear entire cache,
  30. * which can have a performance impact. Flow additions/deletions
  31. * are bundled together over 100ms to save HW cycles if upper layer
  32. * adds/deletes multiple flows together. Use a longer timeout during setup
  33. * stage since no flows are anticipated at this time.
  34. */
  35. #define HW_RX_FSE_CACHE_INVALIDATE_BUNDLE_PERIOD_MS (100)
  36. #define HW_RX_FSE_CACHE_INVALIDATE_DELAYED_FST_SETUP_MS (5000)
  37. /**
  38. * dp_rx_flow_get_fse() - Obtain flow search entry from flow hash
  39. * @fst: Rx FST Handle
  40. * @flow_hash: Computed hash value of flow
  41. *
  42. * Return: Handle to flow search table entry
  43. */
  44. static inline struct dp_rx_fse *
  45. dp_rx_flow_get_fse(struct dp_rx_fst *fst, uint32_t flow_hash)
  46. {
  47. struct dp_rx_fse *fse;
  48. uint32_t idx = hal_rx_get_hal_hash(fst->hal_rx_fst, flow_hash);
  49. fse = (struct dp_rx_fse *)((uint8_t *)fst->base + (idx *
  50. sizeof(struct dp_rx_fse)));
  51. return fse;
  52. }
  53. /**
  54. * dp_rx_flow_dump_flow_entry() - Print flow search entry from 5-tuple
  55. * @fst: Rx FST Handle
  56. * @flow_info: Flow 5-tuple
  57. *
  58. * Return: None
  59. */
  60. void dp_rx_flow_dump_flow_entry(struct dp_rx_fst *fst,
  61. struct cdp_rx_flow_info *flow_info)
  62. {
  63. dp_info("Dest IP address %x:%x:%x:%x",
  64. flow_info->flow_tuple_info.dest_ip_127_96,
  65. flow_info->flow_tuple_info.dest_ip_95_64,
  66. flow_info->flow_tuple_info.dest_ip_63_32,
  67. flow_info->flow_tuple_info.dest_ip_31_0);
  68. dp_info("Source IP address %x:%x:%x:%x",
  69. flow_info->flow_tuple_info.src_ip_127_96,
  70. flow_info->flow_tuple_info.src_ip_95_64,
  71. flow_info->flow_tuple_info.src_ip_63_32,
  72. flow_info->flow_tuple_info.src_ip_31_0);
  73. dp_info("Dest port %u, Src Port %u, Protocol %u",
  74. flow_info->flow_tuple_info.dest_port,
  75. flow_info->flow_tuple_info.src_port,
  76. flow_info->flow_tuple_info.l4_protocol);
  77. }
  78. /**
  79. * dp_rx_flow_compute_flow_hash() - Print flow search entry from 5-tuple
  80. * @fst: Rx FST Handle
  81. * @rx_flow_info: DP Rx Flow 5-tuple programmed by upper layer
  82. * @flow: HAL (HW) flow entry
  83. *
  84. * Return: Computed Toeplitz hash
  85. */
  86. uint32_t dp_rx_flow_compute_flow_hash(struct dp_rx_fst *fst,
  87. struct cdp_rx_flow_info *rx_flow_info,
  88. struct hal_rx_flow *flow)
  89. {
  90. flow->tuple_info.dest_ip_127_96 =
  91. rx_flow_info->flow_tuple_info.dest_ip_127_96;
  92. flow->tuple_info.dest_ip_95_64 =
  93. rx_flow_info->flow_tuple_info.dest_ip_95_64;
  94. flow->tuple_info.dest_ip_63_32 =
  95. rx_flow_info->flow_tuple_info.dest_ip_63_32;
  96. flow->tuple_info.dest_ip_31_0 =
  97. rx_flow_info->flow_tuple_info.dest_ip_31_0;
  98. flow->tuple_info.src_ip_127_96 =
  99. rx_flow_info->flow_tuple_info.src_ip_127_96;
  100. flow->tuple_info.src_ip_95_64 =
  101. rx_flow_info->flow_tuple_info.src_ip_95_64;
  102. flow->tuple_info.src_ip_63_32 =
  103. rx_flow_info->flow_tuple_info.src_ip_63_32;
  104. flow->tuple_info.src_ip_31_0 =
  105. rx_flow_info->flow_tuple_info.src_ip_31_0;
  106. flow->tuple_info.dest_port =
  107. rx_flow_info->flow_tuple_info.dest_port;
  108. flow->tuple_info.src_port =
  109. rx_flow_info->flow_tuple_info.src_port;
  110. flow->tuple_info.l4_protocol =
  111. rx_flow_info->flow_tuple_info.l4_protocol;
  112. return hal_flow_toeplitz_hash(fst->hal_rx_fst, flow);
  113. }
  114. /**
  115. * dp_rx_flow_alloc_entry() - Create DP and HAL flow entries in FST
  116. * @fst: Rx FST Handle
  117. * @rx_flow_info: DP Rx Flow 5-tuple to be added to DP FST
  118. * @flow: HAL (HW) flow entry that is created
  119. *
  120. * Return: Computed Toeplitz hash
  121. */
  122. struct dp_rx_fse *dp_rx_flow_alloc_entry(struct dp_rx_fst *fst,
  123. struct cdp_rx_flow_info *rx_flow_info,
  124. struct hal_rx_flow *flow)
  125. {
  126. struct dp_rx_fse *fse = NULL;
  127. uint32_t flow_hash;
  128. uint32_t flow_idx;
  129. QDF_STATUS status;
  130. flow_hash = dp_rx_flow_compute_flow_hash(fst, rx_flow_info, flow);
  131. status = hal_rx_insert_flow_entry(fst->hal_rx_fst,
  132. flow_hash,
  133. &rx_flow_info->flow_tuple_info,
  134. &flow_idx);
  135. if (status != QDF_STATUS_SUCCESS) {
  136. dp_err("Add entry failed with status %d for tuple with hash %u",
  137. status, flow_hash);
  138. return NULL;
  139. }
  140. fse = dp_rx_flow_get_fse(fst, flow_idx);
  141. fse->is_ipv4_addr_entry = rx_flow_info->is_addr_ipv4;
  142. fse->flow_hash = flow_hash;
  143. fse->flow_id = flow_idx;
  144. fse->stats.msdu_count = 0;
  145. fse->is_valid = true;
  146. return fse;
  147. }
  148. /**
  149. * dp_rx_flow_find_entry_by_tuple() - Find the DP FSE matching a given 5-tuple
  150. * @fst: Rx FST Handle
  151. * @rx_flow_info: DP Rx Flow 5-tuple
  152. * @flow: Pointer to the HAL (HW) flow entry
  153. *
  154. * Return: Pointer to the DP FSE entry
  155. */
  156. struct dp_rx_fse *
  157. dp_rx_flow_find_entry_by_tuple(struct dp_rx_fst *fst,
  158. struct cdp_rx_flow_info *rx_flow_info,
  159. struct hal_rx_flow *flow)
  160. {
  161. uint32_t flow_hash;
  162. uint32_t flow_idx;
  163. QDF_STATUS status;
  164. flow_hash = dp_rx_flow_compute_flow_hash(fst, rx_flow_info, flow);
  165. status = hal_rx_find_flow_from_tuple(fst->hal_rx_fst,
  166. flow_hash,
  167. &rx_flow_info->flow_tuple_info,
  168. &flow_idx);
  169. if (status != QDF_STATUS_SUCCESS) {
  170. dp_err("Could not find tuple with hash %u", flow_hash);
  171. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  172. return NULL;
  173. }
  174. return dp_rx_flow_get_fse(fst, flow_idx);
  175. }
  176. /**
  177. * dp_rx_flow_find_entry_by_flowid() - Find DP FSE matching a given flow index
  178. * @fst: Rx FST Handle
  179. * @flow_id: Flow index of the requested flow
  180. *
  181. * Return: Pointer to the DP FSE entry
  182. */
  183. struct dp_rx_fse *
  184. dp_rx_flow_find_entry_by_flowid(struct dp_rx_fst *fst,
  185. uint32_t flow_id)
  186. {
  187. struct dp_rx_fse *fse = NULL;
  188. fse = dp_rx_flow_get_fse(fst, flow_id);
  189. if (!fse->is_valid)
  190. return NULL;
  191. dp_info("flow_idx= %d, flow_addr = %pK", flow_id, fse);
  192. qdf_assert_always(fse->flow_id == flow_id);
  193. return fse;
  194. }
  195. /**
  196. * dp_rx_flow_send_htt_operation_cmd() - Send HTT FSE command to FW for flow
  197. * addition/removal
  198. * @pdev: Pdev instance
  199. * @op: Add/delete operation
  200. * @info: DP Flow parameters of the flow added/deleted
  201. *
  202. * Return: Success on sending HTT command to FW, error on failure
  203. */
  204. QDF_STATUS dp_rx_flow_send_htt_operation_cmd(struct dp_pdev *pdev,
  205. enum dp_htt_flow_fst_operation op,
  206. struct cdp_rx_flow_info *info)
  207. {
  208. struct dp_htt_rx_flow_fst_operation fst_op;
  209. struct wlan_cfg_dp_soc_ctxt *cfg = pdev->soc->wlan_cfg_ctx;
  210. qdf_mem_set(&fst_op, 0, sizeof(struct dp_htt_rx_flow_fst_operation));
  211. if (qdf_unlikely(wlan_cfg_is_rx_flow_search_table_per_pdev(cfg))) {
  212. /* Firmware pdev ID starts from 1 */
  213. fst_op.pdev_id = DP_SW2HW_MACID(pdev->pdev_id);
  214. } else {
  215. fst_op.pdev_id = 0;
  216. }
  217. fst_op.op_code = op;
  218. fst_op.rx_flow = info;
  219. return dp_htt_rx_flow_fse_operation(pdev, &fst_op);
  220. }
  221. /**
  222. * dp_rx_flow_add_entry() - Add a flow entry to flow search table
  223. * @pdev: DP pdev instance
  224. * @rx_flow_info: DP flow paramaters
  225. *
  226. * Return: Success when flow is added, no-memory or already exists on error
  227. */
  228. QDF_STATUS dp_rx_flow_add_entry(struct dp_pdev *pdev,
  229. struct cdp_rx_flow_info *rx_flow_info)
  230. {
  231. struct hal_rx_flow flow = { 0 };
  232. struct dp_rx_fse *fse;
  233. struct dp_soc *soc = pdev->soc;
  234. struct dp_rx_fst *fst;
  235. fst = pdev->rx_fst;
  236. /* Initialize unused bits in IPv6 address for IPv4 address */
  237. if (rx_flow_info->is_addr_ipv4) {
  238. rx_flow_info->flow_tuple_info.dest_ip_63_32 = 0;
  239. rx_flow_info->flow_tuple_info.dest_ip_95_64 = 0;
  240. rx_flow_info->flow_tuple_info.dest_ip_127_96 =
  241. HAL_IP_DA_SA_PREFIX_IPV4_COMPATIBLE_IPV6;
  242. rx_flow_info->flow_tuple_info.src_ip_63_32 = 0;
  243. rx_flow_info->flow_tuple_info.src_ip_95_64 = 0;
  244. rx_flow_info->flow_tuple_info.src_ip_127_96 =
  245. HAL_IP_DA_SA_PREFIX_IPV4_COMPATIBLE_IPV6;
  246. }
  247. /* Allocate entry in DP FST */
  248. fse = dp_rx_flow_alloc_entry(fst, rx_flow_info, &flow);
  249. if (NULL == fse) {
  250. dp_err("RX FSE alloc failed");
  251. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  252. return QDF_STATUS_E_NOMEM;
  253. }
  254. dp_info("flow_addr = %pK, flow_id = %u, valid = %d, v4 = %d\n",
  255. fse, fse->flow_id, fse->is_valid, fse->is_ipv4_addr_entry);
  256. /* Initialize other parameters for HW flow & populate HW FSE entry */
  257. flow.reo_destination_indication = (fse->flow_hash &
  258. HAL_REO_DEST_IND_HASH_MASK);
  259. /**
  260. * Reo destination of each flow is mapped to match the same used
  261. * by RX Hash algorithm. If RX Hash is disabled, then the REO
  262. * destination below is directly got from pdev, rather than using
  263. * dp_peer_setup_get_reo_hash since we do not have vdev handle here.
  264. */
  265. if (wlan_cfg_is_rx_hash_enabled(soc->wlan_cfg_ctx)) {
  266. flow.reo_destination_indication |=
  267. HAL_REO_DEST_IND_START_OFFSET;
  268. } else {
  269. flow.reo_destination_indication = pdev->reo_dest;
  270. }
  271. flow.reo_destination_handler = HAL_RX_FSE_REO_DEST_FT;
  272. flow.fse_metadata = rx_flow_info->fse_metadata;
  273. fse->hal_rx_fse = hal_rx_flow_setup_fse(fst->hal_rx_fst,
  274. fse->flow_id, &flow);
  275. if (qdf_unlikely(!fse->hal_rx_fse)) {
  276. dp_err("Unable to alloc FSE entry");
  277. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  278. /* Free up the FSE entry as returning failure */
  279. fse->is_valid = false;
  280. return QDF_STATUS_E_EXISTS;
  281. }
  282. /* Increment number of valid entries in table */
  283. fst->num_entries++;
  284. dp_info("FST num_entries = %d, reo_dest_ind = %d, reo_dest_hand = %u",
  285. fst->num_entries, flow.reo_destination_indication,
  286. flow.reo_destination_handler);
  287. if (soc->is_rx_fse_full_cache_invalidate_war_enabled) {
  288. qdf_atomic_set(&fst->is_cache_update_pending, 1);
  289. } else {
  290. QDF_STATUS status;
  291. /**
  292. * Send HTT cache invalidation command to firmware to
  293. * reflect the added flow
  294. */
  295. status = dp_rx_flow_send_htt_operation_cmd(
  296. pdev,
  297. DP_HTT_FST_CACHE_INVALIDATE_ENTRY,
  298. rx_flow_info);
  299. if (QDF_STATUS_SUCCESS != status) {
  300. dp_err("Send cache invalidate entry to fw failed: %u",
  301. status);
  302. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  303. /* Free DP FSE and HAL FSE */
  304. hal_rx_flow_delete_entry(fst->hal_rx_fst,
  305. fse->hal_rx_fse);
  306. fse->is_valid = false;
  307. return status;
  308. }
  309. }
  310. return QDF_STATUS_SUCCESS;
  311. }
  312. /**
  313. * dp_rx_flow_delete_entry() - Delete a flow entry from flow search table
  314. * @pdev: pdev handle
  315. * @rx_flow_info: DP flow parameters
  316. *
  317. * Return: Success when flow is deleted, error on failure
  318. */
  319. QDF_STATUS dp_rx_flow_delete_entry(struct dp_pdev *pdev,
  320. struct cdp_rx_flow_info *rx_flow_info)
  321. {
  322. struct hal_rx_flow flow = { 0 };
  323. struct dp_rx_fse *fse;
  324. struct dp_soc *soc = pdev->soc;
  325. struct dp_rx_fst *fst;
  326. QDF_STATUS status;
  327. fst = pdev->rx_fst;
  328. /* Find the given flow entry DP FST */
  329. fse = dp_rx_flow_find_entry_by_tuple(fst, rx_flow_info, &flow);
  330. if (!fse) {
  331. dp_err("RX flow delete entry failed");
  332. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  333. return QDF_STATUS_E_INVAL;
  334. }
  335. /* Delete the FSE in HW FST */
  336. status = hal_rx_flow_delete_entry(fst->hal_rx_fst, fse->hal_rx_fse);
  337. qdf_assert_always(status == QDF_STATUS_SUCCESS);
  338. /* Free the FSE in DP FST */
  339. fse->is_valid = false;
  340. /* Decrement number of valid entries in table */
  341. fst->num_entries--;
  342. if (soc->is_rx_fse_full_cache_invalidate_war_enabled) {
  343. qdf_atomic_set(&fst->is_cache_update_pending, 1);
  344. } else {
  345. /**
  346. * Send HTT cache invalidation command to firmware
  347. * to reflect the deleted flow
  348. */
  349. status = dp_rx_flow_send_htt_operation_cmd(
  350. pdev,
  351. DP_HTT_FST_CACHE_INVALIDATE_ENTRY,
  352. rx_flow_info);
  353. if (QDF_STATUS_SUCCESS != status) {
  354. dp_err("Send cache invalidate entry to fw failed: %u",
  355. status);
  356. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  357. /* Do not add entry back in DP FSE and HAL FSE */
  358. return status;
  359. }
  360. }
  361. return QDF_STATUS_SUCCESS;
  362. }
  363. /* dp_rx_flow_update_fse_stats() - Update a flow's statistics
  364. * @pdev: pdev handle
  365. * @flow_id: flow index (truncated hash) in the Rx FST
  366. *
  367. * Return: Success when flow statistcs is updated, error on failure
  368. */
  369. QDF_STATUS dp_rx_flow_update_fse_stats(struct dp_pdev *pdev, uint32_t flow_id)
  370. {
  371. struct dp_rx_fse *fse;
  372. fse = dp_rx_flow_find_entry_by_flowid(pdev->rx_fst, flow_id);
  373. if (NULL == fse) {
  374. dp_err("Flow not found, flow ID %u", flow_id);
  375. return QDF_STATUS_E_NOENT;
  376. }
  377. fse->stats.msdu_count += 1;
  378. return QDF_STATUS_SUCCESS;
  379. }
  380. /**
  381. * dp_rx_flow_get_fse_stats() - Fetch a flow's stats based on DP flow parameter
  382. * @pdev: pdev handle
  383. * @rx_flow_info: Pointer to the DP flow struct of the requested flow
  384. * @stats: Matching flow's stats returned to caller
  385. *
  386. * Return: Success when flow statistcs is updated, error on failure
  387. */
  388. QDF_STATUS dp_rx_flow_get_fse_stats(struct dp_pdev *pdev,
  389. struct cdp_rx_flow_info *rx_flow_info,
  390. struct cdp_flow_stats *stats)
  391. {
  392. struct dp_rx_fst *fst;
  393. struct dp_rx_fse *fse;
  394. struct hal_rx_flow flow;
  395. fst = pdev->rx_fst;
  396. /* Find the given flow entry DP FST */
  397. fse = dp_rx_flow_find_entry_by_tuple(fst, rx_flow_info, &flow);
  398. if (!fse) {
  399. dp_err("RX flow entry search failed");
  400. dp_rx_flow_dump_flow_entry(fst, rx_flow_info);
  401. return QDF_STATUS_E_INVAL;
  402. }
  403. stats->msdu_count = fse->stats.msdu_count;
  404. return QDF_STATUS_SUCCESS;
  405. }
  406. /**
  407. * dp_rx_flow_cache_invalidate_timer_handler() - Timer handler used for bundling
  408. * flows before invalidating entire cache
  409. * @ctx: Pdev handle
  410. *
  411. * Return: None
  412. */
  413. void dp_rx_flow_cache_invalidate_timer_handler(void *ctx)
  414. {
  415. struct dp_pdev *pdev = (struct dp_pdev *)ctx;
  416. struct dp_rx_fst *fst;
  417. bool is_update_pending;
  418. QDF_STATUS status;
  419. fst = pdev->rx_fst;
  420. qdf_assert_always(fst);
  421. is_update_pending = qdf_atomic_read(&fst->is_cache_update_pending);
  422. qdf_atomic_set(&fst->is_cache_update_pending, 0);
  423. if (is_update_pending) {
  424. /* Send full cache invalidate command to firmware */
  425. status = dp_rx_flow_send_htt_operation_cmd(
  426. pdev,
  427. DP_HTT_FST_CACHE_INVALIDATE_FULL,
  428. NULL);
  429. if (QDF_STATUS_SUCCESS != status)
  430. dp_err("Send full cache inv to fw failed: %u", status);
  431. }
  432. qdf_timer_start(&fst->cache_invalidate_timer,
  433. HW_RX_FSE_CACHE_INVALIDATE_BUNDLE_PERIOD_MS);
  434. }
  435. /**
  436. * dp_rx_fst_attach() - Initialize Rx FST and setup necessary parameters
  437. * @soc: SoC handle
  438. * @pdev: Pdev handle
  439. *
  440. * Return: Handle to flow search table entry
  441. */
  442. QDF_STATUS dp_rx_fst_attach(struct dp_soc *soc, struct dp_pdev *pdev)
  443. {
  444. struct dp_rx_fst *fst;
  445. uint8_t *hash_key;
  446. struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
  447. bool is_rx_flow_search_table_per_pdev =
  448. wlan_cfg_is_rx_flow_search_table_per_pdev(cfg);
  449. if (qdf_unlikely(!wlan_cfg_is_rx_flow_tag_enabled(cfg))) {
  450. dp_err("RX Flow tag feature disabled");
  451. return QDF_STATUS_E_NOSUPPORT;
  452. }
  453. if (!wlan_psoc_nif_fw_ext_cap_get((void *)pdev->ctrl_pdev,
  454. WLAN_SOC_CEXT_RX_FSE_SUPPORT)) {
  455. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  456. "rx fse disabled in FW\n");
  457. wlan_cfg_set_rx_flow_tag_enabled(cfg, false);
  458. return QDF_STATUS_E_NOSUPPORT;
  459. }
  460. /**
  461. * Func. is called for every pdev. If FST is per SOC, then return
  462. * if it was already called once.
  463. */
  464. if (!is_rx_flow_search_table_per_pdev && soc->rx_fst) {
  465. pdev->rx_fst = soc->rx_fst;
  466. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  467. "RX FST for SoC is already initialized");
  468. return QDF_STATUS_SUCCESS;
  469. }
  470. /**
  471. * Func. is called for this pdev already. This is an error.
  472. * Return failure
  473. */
  474. if (is_rx_flow_search_table_per_pdev && pdev->rx_fst) {
  475. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  476. "RX FST for PDEV %u is already initialized",
  477. pdev->pdev_id);
  478. return QDF_STATUS_E_EXISTS;
  479. }
  480. fst = qdf_mem_malloc(sizeof(struct dp_rx_fst));
  481. if (!fst) {
  482. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  483. "RX FST allocation failed\n");
  484. return QDF_STATUS_E_NOMEM;
  485. }
  486. qdf_mem_set(fst, 0, sizeof(struct dp_rx_fst));
  487. fst->max_skid_length = wlan_cfg_rx_fst_get_max_search(cfg);
  488. fst->max_entries = wlan_cfg_get_rx_flow_search_table_size(cfg);
  489. hash_key = wlan_cfg_rx_fst_get_hash_key(cfg);
  490. if (!(fst->max_entries &&
  491. (!(fst->max_entries & (fst->max_entries - 1))))) {
  492. uint32_t next_power_of_2 = fst->max_entries - 1;
  493. next_power_of_2 |= (next_power_of_2 >> 1);
  494. next_power_of_2 |= (next_power_of_2 >> 2);
  495. next_power_of_2 |= (next_power_of_2 >> 4);
  496. next_power_of_2 |= (next_power_of_2 >> 8);
  497. next_power_of_2 |= (next_power_of_2 >> 16);
  498. next_power_of_2++;
  499. if (next_power_of_2 > WLAN_CFG_RX_FLOW_SEARCH_TABLE_SIZE_MAX)
  500. next_power_of_2 =
  501. WLAN_CFG_RX_FLOW_SEARCH_TABLE_SIZE_MAX;
  502. dp_info("Num entries in cfg is not a ^2:%u, using next ^2:%u",
  503. fst->max_entries, next_power_of_2);
  504. fst->max_entries = next_power_of_2;
  505. }
  506. fst->hash_mask = fst->max_entries - 1;
  507. fst->num_entries = 0;
  508. fst->base = (uint8_t *) qdf_mem_malloc(sizeof(struct dp_rx_fse) *
  509. fst->max_entries);
  510. if (!fst->base) {
  511. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  512. "Rx fst->base allocation failed, #entries:%d\n",
  513. fst->max_entries);
  514. qdf_mem_free(fst);
  515. return QDF_STATUS_E_NOMEM;
  516. }
  517. qdf_mem_set((uint8_t *)fst->base, 0,
  518. (sizeof(struct dp_rx_fse) * fst->max_entries));
  519. fst->hal_rx_fst = hal_rx_fst_attach(
  520. soc->osdev,
  521. &fst->hal_rx_fst_base_paddr,
  522. fst->max_entries,
  523. fst->max_skid_length,
  524. hash_key);
  525. if (qdf_unlikely(!fst->hal_rx_fst)) {
  526. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  527. "Rx Hal fst allocation failed, #entries:%d\n",
  528. fst->max_entries);
  529. qdf_mem_free(fst->base);
  530. qdf_mem_free(fst);
  531. return QDF_STATUS_E_NOMEM;
  532. }
  533. if (!is_rx_flow_search_table_per_pdev)
  534. soc->rx_fst = fst;
  535. pdev->rx_fst = fst;
  536. if (soc->is_rx_fse_full_cache_invalidate_war_enabled) {
  537. QDF_STATUS status;
  538. status = qdf_timer_init(
  539. soc->osdev,
  540. &fst->cache_invalidate_timer,
  541. dp_rx_flow_cache_invalidate_timer_handler,
  542. (void *)pdev,
  543. QDF_TIMER_TYPE_SW);
  544. qdf_assert_always(status == QDF_STATUS_SUCCESS);
  545. /* Start the timer */
  546. qdf_timer_start(
  547. &fst->cache_invalidate_timer,
  548. HW_RX_FSE_CACHE_INVALIDATE_DELAYED_FST_SETUP_MS);
  549. qdf_atomic_set(&fst->is_cache_update_pending, false);
  550. }
  551. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_INFO,
  552. "Rx FST attach successful, #entries:%d\n",
  553. fst->max_entries);
  554. return QDF_STATUS_SUCCESS;
  555. }
  556. /**
  557. * dp_rx_fst_detach() - De-initialize Rx FST
  558. * @soc: SoC handle
  559. * @pdev: Pdev handle
  560. *
  561. * Return: None
  562. */
  563. void dp_rx_fst_detach(struct dp_soc *soc, struct dp_pdev *pdev)
  564. {
  565. struct dp_rx_fst *dp_fst;
  566. struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
  567. if (qdf_unlikely(wlan_cfg_is_rx_flow_search_table_per_pdev(cfg))) {
  568. dp_fst = pdev->rx_fst;
  569. pdev->rx_fst = NULL;
  570. } else {
  571. dp_fst = soc->rx_fst;
  572. soc->rx_fst = NULL;
  573. }
  574. if (qdf_likely(dp_fst)) {
  575. hal_rx_fst_detach(dp_fst->hal_rx_fst, soc->osdev);
  576. if (soc->is_rx_fse_full_cache_invalidate_war_enabled) {
  577. qdf_timer_sync_cancel(&dp_fst->cache_invalidate_timer);
  578. qdf_timer_stop(&dp_fst->cache_invalidate_timer);
  579. qdf_timer_free(&dp_fst->cache_invalidate_timer);
  580. }
  581. qdf_mem_free(dp_fst->base);
  582. qdf_mem_free(dp_fst);
  583. }
  584. QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
  585. "Rx FST detached for pdev %u\n", pdev->pdev_id);
  586. }
  587. /**
  588. * dp_rx_flow_send_fst_fw_setup() - Program FST parameters in FW/HW post-attach
  589. * @soc: SoC handle
  590. * @pdev: Pdev handle
  591. *
  592. * Return: Success when fst parameters are programmed in FW, error otherwise
  593. */
  594. QDF_STATUS dp_rx_flow_send_fst_fw_setup(struct dp_soc *soc,
  595. struct dp_pdev *pdev)
  596. {
  597. struct dp_htt_rx_flow_fst_setup fst_setup;
  598. struct dp_rx_fst *fst;
  599. QDF_STATUS status;
  600. struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
  601. if (qdf_unlikely(!wlan_cfg_is_rx_flow_tag_enabled(cfg)))
  602. return QDF_STATUS_SUCCESS;
  603. qdf_mem_set(&fst_setup, 0, sizeof(struct dp_htt_rx_flow_fst_setup));
  604. if (qdf_unlikely(wlan_cfg_is_rx_flow_search_table_per_pdev(cfg))) {
  605. /* Firmware pdev ID starts from 1 */
  606. fst_setup.pdev_id = DP_SW2HW_MACID(pdev->pdev_id);
  607. fst = pdev->rx_fst;
  608. } else {
  609. fst_setup.pdev_id = 0;
  610. fst = soc->rx_fst;
  611. }
  612. fst_setup.max_entries = fst->max_entries;
  613. fst_setup.max_search = fst->max_skid_length;
  614. fst_setup.base_addr_lo = (uint32_t)fst->hal_rx_fst_base_paddr;
  615. fst_setup.base_addr_hi =
  616. (uint32_t)((uint64_t)fst->hal_rx_fst_base_paddr >> 32);
  617. fst_setup.ip_da_sa_prefix =
  618. HAL_FST_IP_DA_SA_PFX_TYPE_IPV4_COMPATIBLE_IPV6;
  619. fst_setup.hash_key = wlan_cfg_rx_fst_get_hash_key(cfg);
  620. fst_setup.hash_key_len = HAL_FST_HASH_KEY_SIZE_BYTES;
  621. status = dp_htt_rx_flow_fst_setup(pdev, &fst_setup);
  622. if (status == QDF_STATUS_SUCCESS) {
  623. fst->fse_setup_done = true;
  624. return status;
  625. }
  626. QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
  627. "Failed to send Rx FSE Setup pdev%d status %d\n",
  628. pdev->pdev_id, status);
  629. /* Free all the memory allocations and data structures */
  630. dp_rx_fst_detach(pdev->soc, pdev);
  631. return status;
  632. }
  633. #endif /* WLAN_SUPPORT_RX_FLOW_TAG */