qcacmn: Move flow learning and operation HAL macros out of header file

Move flow learning and operation HAL macros from header file hal_rx_flow.h
to hal_rx_flow.c.
1) hal_rx_flow.c conditionally compiled in based on the feature
2) Function implementations are too big to be defined in hal_rx_flow.h

Replicate hal_rx_flow_setup_fse specific to FISA Flow programming.
Implement function to dump the FT entries.

Change-Id: I7db943495eecfc064c4b696939da83d1d8ed9280
CRs-Fixed: 2599917
diff --git a/hal/wifi3.0/hal_rx_flow.c b/hal/wifi3.0/hal_rx_flow.c
new file mode 100644
index 0000000..43a1449
--- /dev/null
+++ b/hal/wifi3.0/hal_rx_flow.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "qdf_module.h"
+#include "dp_types.h"
+#include "hal_rx_flow.h"
+
+#if defined(WLAN_SUPPORT_RX_FISA)
+void hal_rx_dump_fse_table(struct hal_rx_fst *fst)
+{
+	int i = 0;
+	struct rx_flow_search_entry *fse =
+		(struct rx_flow_search_entry *)fst->base_vaddr;
+
+	dp_info("Number flow table entries %d", fst->add_flow_count);
+	for (i = 0; i < fst->max_entries; i++) {
+		if (fse[i].valid) {
+			dp_info("index %d:"
+			" src_ip_127_96 0x%x"
+			" src_ip_95_640 0x%x"
+			" src_ip_63_32 0x%x"
+			" src_ip_31_0 0x%x"
+			" dest_ip_127_96 0x%x"
+			" dest_ip_95_64 0x%x"
+			" dest_ip_63_32 0x%x"
+			" dest_ip_31_0 0x%x"
+			" src_port 0x%x"
+			" dest_port 0x%x"
+			" l4_protocol 0x%x"
+			" valid 0x%x"
+			" reo_destination_indication 0x%x"
+			" msdu_drop 0x%x"
+			" reo_destination_handler 0x%x"
+			" metadata 0x%x"
+			" aggregation_count0x%x"
+			" lro_eligible 0x%x"
+			" msdu_count 0x%x"
+			" msdu_byte_count 0x%x"
+			" timestamp 0x%x"
+			" cumulative_l4_checksum 0x%x"
+			" cumulative_ip_length 0x%x"
+			" tcp_sequence_number 0x%x",
+			i,
+			fse[i].src_ip_127_96,
+			fse[i].src_ip_95_64,
+			fse[i].src_ip_63_32,
+			fse[i].src_ip_31_0,
+			fse[i].dest_ip_127_96,
+			fse[i].dest_ip_95_64,
+			fse[i].dest_ip_63_32,
+			fse[i].dest_ip_31_0,
+			fse[i].src_port,
+			fse[i].dest_port,
+			fse[i].l4_protocol,
+			fse[i].valid,
+			fse[i].reo_destination_indication,
+			fse[i].msdu_drop,
+			fse[i].reo_destination_handler,
+			fse[i].metadata,
+			fse[i].aggregation_count,
+			fse[i].lro_eligible,
+			fse[i].msdu_count,
+			fse[i].msdu_byte_count,
+			fse[i].timestamp,
+			fse[i].cumulative_l4_checksum,
+			fse[i].cumulative_ip_length,
+			fse[i].tcp_sequence_number);
+		}
+	}
+}
+#else
+void hal_rx_dump_fse_table(struct hal_rx_fst *fst)
+{
+}
+#endif
+
+/**
+ * hal_rx_flow_setup_fse() - Setup a flow search entry in HW FST
+ * @fst: Pointer to the Rx Flow Search Table
+ * @table_offset: offset into the table where the flow is to be setup
+ * @flow: Flow Parameters
+ *
+ * Return: Success/Failure
+ */
+#ifdef WLAN_SUPPORT_RX_FLOW_TAG
+void *
+hal_rx_flow_setup_fse(struct hal_rx_fst *fst, uint32_t table_offset,
+		      struct hal_rx_flow *flow)
+{
+	uint8_t *fse;
+	bool fse_valid;
+
+	if (table_offset >= fst->max_entries) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			  "HAL FSE table offset %u exceeds max entries %u",
+			  table_offset, fst->max_entries);
+		return NULL;
+	}
+
+	fse = (uint8_t *)fst->base_vaddr +
+			(table_offset * HAL_RX_FST_ENTRY_SIZE);
+
+	fse_valid = HAL_GET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
+
+	if (fse_valid) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+			  "HAL FSE %pK already valid", fse);
+		return NULL;
+	}
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96,
+			       qdf_htonl(flow->tuple_info.src_ip_127_96));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64,
+			       qdf_htonl(flow->tuple_info.src_ip_95_64));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32,
+			       qdf_htonl(flow->tuple_info.src_ip_63_32));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0,
+			       qdf_htonl(flow->tuple_info.src_ip_31_0));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96,
+			       qdf_htonl(flow->tuple_info.dest_ip_127_96));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64,
+			       qdf_htonl(flow->tuple_info.dest_ip_95_64));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32,
+			       qdf_htonl(flow->tuple_info.dest_ip_63_32));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0,
+			       qdf_htonl(flow->tuple_info.dest_ip_31_0));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, DEST_PORT);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, DEST_PORT) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_8, DEST_PORT,
+			       (flow->tuple_info.dest_port));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, SRC_PORT);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, SRC_PORT) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_8, SRC_PORT,
+			       (flow->tuple_info.src_port));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL,
+			       flow->tuple_info.l4_protocol);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER,
+			       flow->reo_destination_handler);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, VALID, 1);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_10, METADATA);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_10, METADATA) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_10, METADATA,
+			       flow->fse_metadata);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, REO_DESTINATION_INDICATION);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, REO_DESTINATION_INDICATION) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_11,
+			       REO_DESTINATION_INDICATION,
+			       flow->reo_destination_indication);
+
+	/* Reset all the other fields in FSE */
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, RESERVED_9);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, MSDU_DROP);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, RESERVED_11);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, MSDU_COUNT);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_12, MSDU_BYTE_COUNT);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_13, TIMESTAMP);
+
+	return fse;
+}
+#elif defined(WLAN_SUPPORT_RX_FISA)
+/**
+ * hal_rx_flow_setup_fse() - Setup a flow search entry in HW FST
+ * @fst: Pointer to the Rx Flow Search Table
+ * @table_offset: offset into the table where the flow is to be setup
+ * @flow: Flow Parameters
+ *
+ * Flow table entry fields are updated in host byte order, little endian order.
+ *
+ * Return: Success/Failure
+ */
+void *
+hal_rx_flow_setup_fse(struct hal_rx_fst *fst, uint32_t table_offset,
+		      struct hal_rx_flow *flow)
+{
+	uint8_t *fse;
+	bool fse_valid;
+
+	if (table_offset >= fst->max_entries) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			  "HAL FSE table offset %u exceeds max entries %u",
+			  table_offset, fst->max_entries);
+		return NULL;
+	}
+
+	fse = (uint8_t *)fst->base_vaddr +
+			(table_offset * HAL_RX_FST_ENTRY_SIZE);
+
+	fse_valid = HAL_GET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
+
+	if (fse_valid) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+			  "HAL FSE %pK already valid", fse);
+		return NULL;
+	}
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_0, SRC_IP_127_96,
+			       (flow->tuple_info.src_ip_127_96));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_1, SRC_IP_95_64,
+			       (flow->tuple_info.src_ip_95_64));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_2, SRC_IP_63_32,
+			       (flow->tuple_info.src_ip_63_32));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_3, SRC_IP_31_0,
+			       (flow->tuple_info.src_ip_31_0));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_4, DEST_IP_127_96,
+			       (flow->tuple_info.dest_ip_127_96));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_5, DEST_IP_95_64,
+			       (flow->tuple_info.dest_ip_95_64));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_6, DEST_IP_63_32,
+			       (flow->tuple_info.dest_ip_63_32));
+
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_7, DEST_IP_31_0,
+			       (flow->tuple_info.dest_ip_31_0));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, DEST_PORT);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, DEST_PORT) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_8, DEST_PORT,
+			       (flow->tuple_info.dest_port));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, SRC_PORT);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_8, SRC_PORT) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_8, SRC_PORT,
+			       (flow->tuple_info.src_port));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, L4_PROTOCOL,
+			       flow->tuple_info.l4_protocol);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_HANDLER,
+			       flow->reo_destination_handler);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9, VALID, 1);
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_10, METADATA);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_10, METADATA) =
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_10, METADATA,
+			       (flow->fse_metadata));
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_INDICATION);
+	HAL_SET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, REO_DESTINATION_INDICATION) |=
+		HAL_SET_FLD_SM(RX_FLOW_SEARCH_ENTRY_9,
+			       REO_DESTINATION_INDICATION,
+			       flow->reo_destination_indication);
+
+	/* Reset all the other fields in FSE */
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, RESERVED_9);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, MSDU_DROP);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_11, MSDU_COUNT);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_12, MSDU_BYTE_COUNT);
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_13, TIMESTAMP);
+
+	return fse;
+}
+#endif /* WLAN_SUPPORT_RX_FISA */
+qdf_export_symbol(hal_rx_flow_setup_fse);
+
+/**
+ * hal_rx_flow_delete_entry() - Delete a flow from the Rx Flow Search Table
+ * @fst: Pointer to the Rx Flow Search Table
+ * @hal_rx_fse: Pointer to the Rx Flow that is to be deleted from the FST
+ *
+ * Return: Success/Failure
+ */
+inline QDF_STATUS
+hal_rx_flow_delete_entry(struct hal_rx_fst *fst, void *hal_rx_fse)
+{
+	uint8_t *fse = (uint8_t *)hal_rx_fse;
+
+	if (!HAL_GET_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID))
+		return QDF_STATUS_E_NOENT;
+
+	HAL_CLR_FLD(fse, RX_FLOW_SEARCH_ENTRY_9, VALID);
+
+	return QDF_STATUS_SUCCESS;
+}
+qdf_export_symbol(hal_rx_flow_delete_entry);
+
+/**
+ * hal_rx_fst_key_configure() - Configure the Toeplitz key in the FST
+ * @fst: Pointer to the Rx Flow Search Table
+ *
+ * Return: Success/Failure
+ */
+static void hal_rx_fst_key_configure(struct hal_rx_fst *fst)
+{
+	uint8_t key_bytes[HAL_FST_HASH_KEY_SIZE_BYTES];
+
+	qdf_mem_copy(key_bytes, fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
+
+	/**
+	 * The Toeplitz algorithm as per the Microsoft spec works in a
+	 * “big-endian” manner, using the MSBs of the key to hash the
+	 * initial bytes of the input going on to use up the lower order bits
+	 * of the key to hash further bytes of the input until the LSBs of the
+	 * key are used finally.
+	 *
+	 * So first, rightshift 320-bit input key 5 times to get 315 MS bits
+	 */
+	key_bitwise_shift_left(key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES, 5);
+	key_reverse(fst->shifted_key, key_bytes, HAL_FST_HASH_KEY_SIZE_BYTES);
+}
+
+/**
+ * hal_rx_fst_get_base() - Retrieve the virtual base address of the Rx FST
+ * @fst: Pointer to the Rx Flow Search Table
+ *
+ * Return: Success/Failure
+ */
+static inline void *hal_rx_fst_get_base(struct hal_rx_fst *fst)
+{
+	return fst->base_vaddr;
+}
+
+/**
+ * hal_rx_fst_get_fse_size() - Retrieve the size of each entry(flow) in Rx FST
+ *
+ * Return: size of each entry/flow in Rx FST
+ */
+static inline uint32_t hal_rx_fst_get_fse_size(void)
+{
+	return HAL_RX_FST_ENTRY_SIZE;
+}
+
+/**
+ * hal_rx_flow_get_tuple_info() - Retrieve the 5-tuple flow info for an entry
+ * @hal_fse: Pointer to the Flow in Rx FST
+ * @tuple_info: 5-tuple info of the flow returned to the caller
+ *
+ * Return: Success/Failure
+ */
+QDF_STATUS hal_rx_flow_get_tuple_info(void *hal_fse,
+				      struct hal_flow_tuple_info *tuple_info)
+{
+	if (!hal_fse || !tuple_info)
+		return QDF_STATUS_E_INVAL;
+
+	if (!HAL_GET_FLD(hal_fse, RX_FLOW_SEARCH_ENTRY_9, VALID))
+		return QDF_STATUS_E_NOENT;
+
+	tuple_info->src_ip_127_96 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_0,
+						      SRC_IP_127_96));
+	tuple_info->src_ip_95_64 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_1,
+						      SRC_IP_95_64));
+	tuple_info->src_ip_63_32 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_2,
+						      SRC_IP_63_32));
+	tuple_info->src_ip_31_0 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_3,
+						      SRC_IP_31_0));
+	tuple_info->dest_ip_127_96 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_4,
+						      DEST_IP_127_96));
+	tuple_info->dest_ip_95_64 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_5,
+						      DEST_IP_95_64));
+	tuple_info->dest_ip_63_32 =
+				qdf_ntohl(HAL_GET_FLD(hal_fse,
+						      RX_FLOW_SEARCH_ENTRY_6,
+						      DEST_IP_63_32));
+	tuple_info->dest_ip_31_0 =
+			qdf_ntohl(HAL_GET_FLD(hal_fse,
+					      RX_FLOW_SEARCH_ENTRY_7,
+					      DEST_IP_31_0));
+	tuple_info->dest_port = HAL_GET_FLD(hal_fse,
+					    RX_FLOW_SEARCH_ENTRY_8,
+					    DEST_PORT);
+	tuple_info->src_port = HAL_GET_FLD(hal_fse,
+					   RX_FLOW_SEARCH_ENTRY_8,
+					   SRC_PORT);
+	tuple_info->l4_protocol = HAL_GET_FLD(hal_fse,
+					      RX_FLOW_SEARCH_ENTRY_9,
+					      L4_PROTOCOL);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * hal_flow_toeplitz_create_cache() - Calculate hashes for each possible
+ * byte value with the key taken as is
+ *
+ * @fst: FST Handle
+ * @key: Hash Key
+ *
+ * Return: Success/Failure
+ */
+static void hal_flow_toeplitz_create_cache(struct hal_rx_fst *fst)
+{
+	int bit;
+	int val;
+	int i;
+	uint8_t *key = fst->shifted_key;
+
+	/*
+	 * Initialise to first 32 bits of the key; shift in further key material
+	 * through the loop
+	 */
+	uint32_t cur_key = (key[0] << 24) | (key[1] << 16) | (key[2] << 8) |
+		key[3];
+
+	for (i = 0; i < HAL_FST_HASH_KEY_SIZE_BYTES; i++) {
+		uint8_t new_key_byte;
+		uint32_t shifted_key[8];
+
+		if (i + 4 < HAL_FST_HASH_KEY_SIZE_BYTES)
+			new_key_byte = key[i + 4];
+		else
+			new_key_byte = 0;
+
+		shifted_key[0] = cur_key;
+
+		for (bit = 1; bit < 8; bit++) {
+			/*
+			 * For each iteration, shift out one more bit of the
+			 * current key and shift in one more bit of the new key
+			 * material
+			 */
+			shifted_key[bit] = cur_key << bit |
+				new_key_byte >> (8 - bit);
+		}
+
+		for (val = 0; val < (1 << 8); val++) {
+			uint32_t hash = 0;
+			int mask;
+
+			/*
+			 * For each bit set in the input, XOR in
+			 * the appropriately shifted key
+			 */
+			for (bit = 0, mask = 1 << 7; bit < 8; bit++, mask >>= 1)
+				if ((val & mask))
+					hash ^= shifted_key[bit];
+
+			fst->key_cache[i][val] = hash;
+		}
+
+		cur_key = cur_key << 8 | new_key_byte;
+	}
+}
+
+/**
+ * hal_rx_fst_attach() - Initialize Rx flow search table in HW FST
+ *
+ * @qdf_dev: QDF device handle
+ * @hal_fst_base_paddr: Pointer to the physical base address of the Rx FST
+ * @max_entries: Max number of flows allowed in the FST
+ * @max_search: Number of collisions allowed in the hash-based FST
+ * @hash_key: Toeplitz key used for the hash FST
+ *
+ * Return:
+ */
+struct hal_rx_fst *
+hal_rx_fst_attach(qdf_device_t qdf_dev,
+		  uint64_t *hal_fst_base_paddr, uint16_t max_entries,
+		  uint16_t max_search, uint8_t *hash_key)
+{
+	struct hal_rx_fst *fst = qdf_mem_malloc(sizeof(struct hal_rx_fst));
+
+	if (!fst) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			  FL("hal fst allocation failed,"));
+		return NULL;
+	}
+
+	qdf_mem_set(fst, 0, sizeof(struct hal_rx_fst));
+
+	fst->key = hash_key;
+	fst->max_skid_length = max_search;
+	fst->max_entries = max_entries;
+	fst->hash_mask = max_entries - 1;
+
+	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+		  "HAL FST allocation %x %d * %d\n", fst,
+		  fst->max_entries, HAL_RX_FST_ENTRY_SIZE);
+
+	fst->base_vaddr = (uint8_t *)qdf_mem_alloc_consistent(qdf_dev,
+				qdf_dev->dev,
+				(fst->max_entries * HAL_RX_FST_ENTRY_SIZE),
+				&fst->base_paddr);
+
+	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
+		  "hal_rx_fst base address 0x%x", fst->base_paddr);
+	if (!fst->base_vaddr) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			  FL("hal fst->base_vaddr allocation failed"));
+		qdf_mem_free(fst);
+		return NULL;
+	}
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_DEBUG,
+			   (void *)fst->key, HAL_FST_HASH_KEY_SIZE_BYTES);
+
+	qdf_mem_set((uint8_t *)fst->base_vaddr, 0,
+		    (fst->max_entries * HAL_RX_FST_ENTRY_SIZE));
+
+	hal_rx_fst_key_configure(fst);
+	hal_flow_toeplitz_create_cache(fst);
+	*hal_fst_base_paddr = (uint64_t)fst->base_paddr;
+	return fst;
+}
+qdf_export_symbol(hal_rx_fst_attach);
+
+/**
+ * hal_rx_fst_detach() - De-init the Rx flow search table from HW
+ *
+ * @rx_fst: Pointer to the Rx FST
+ * @qdf_dev: QDF device handle
+ *
+ * Return:
+ */
+void hal_rx_fst_detach(struct hal_rx_fst *rx_fst,
+		       qdf_device_t qdf_dev)
+{
+	if (!rx_fst || !qdf_dev)
+		return;
+
+	qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
+				rx_fst->max_entries * HAL_RX_FST_ENTRY_SIZE,
+				rx_fst->base_vaddr, rx_fst->base_paddr, 0);
+
+	qdf_mem_free(rx_fst);
+}
+qdf_export_symbol(hal_rx_fst_detach);
+
+/**
+ * hal_flow_toeplitz_hash() - Calculate Toeplitz hash by using the cached key
+ *
+ * @hal_fst: FST Handle
+ * @flow: Flow Parameters
+ *
+ * Return: Success/Failure
+ */
+uint32_t
+hal_flow_toeplitz_hash(void *hal_fst, struct hal_rx_flow *flow)
+{
+	int i, j;
+	uint32_t hash = 0;
+	struct hal_rx_fst *fst = (struct hal_rx_fst *)hal_fst;
+	uint32_t input[HAL_FST_HASH_KEY_SIZE_WORDS];
+	uint8_t *tuple;
+
+	qdf_mem_zero(input, HAL_FST_HASH_KEY_SIZE_BYTES);
+	*(uint32_t *)&input[0] = qdf_htonl(flow->tuple_info.src_ip_127_96);
+	*(uint32_t *)&input[1] = qdf_htonl(flow->tuple_info.src_ip_95_64);
+	*(uint32_t *)&input[2] = qdf_htonl(flow->tuple_info.src_ip_63_32);
+	*(uint32_t *)&input[3] = qdf_htonl(flow->tuple_info.src_ip_31_0);
+	*(uint32_t *)&input[4] = qdf_htonl(flow->tuple_info.dest_ip_127_96);
+	*(uint32_t *)&input[5] = qdf_htonl(flow->tuple_info.dest_ip_95_64);
+	*(uint32_t *)&input[6] = qdf_htonl(flow->tuple_info.dest_ip_63_32);
+	*(uint32_t *)&input[7] = qdf_htonl(flow->tuple_info.dest_ip_31_0);
+	*(uint32_t *)&input[8] = (flow->tuple_info.dest_port << 16) |
+				 (flow->tuple_info.src_port);
+	*(uint32_t *)&input[9] = flow->tuple_info.l4_protocol;
+
+	tuple = (uint8_t *)input;
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			   tuple, sizeof(input));
+	for (i = 0, j = HAL_FST_HASH_DATA_SIZE - 1;
+	     i < HAL_FST_HASH_KEY_SIZE_BYTES && j >= 0; i++, j--) {
+		hash ^= fst->key_cache[i][tuple[j]];
+	}
+
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_LOW,
+		  "Hash value %u %u truncated hash %u\n", hash,
+		  (hash >> 12), (hash >> 12) % (fst->max_entries));
+
+	hash >>= 12;
+	hash &= (fst->max_entries - 1);
+
+	return hash;
+}
+qdf_export_symbol(hal_flow_toeplitz_hash);
+
+/**
+ * hal_rx_get_hal_hash() - Retrieve hash index of a flow in the FST table
+ *
+ * @hal_fst: HAL Rx FST Handle
+ * @flow_hash: Flow hash computed from flow tuple
+ *
+ * Return: hash index truncated to the size of the hash table
+ */
+uint32_t hal_rx_get_hal_hash(struct hal_rx_fst *hal_fst, uint32_t flow_hash)
+{
+	uint32_t trunc_hash = flow_hash;
+
+	/* Take care of hash wrap around scenario */
+	if (flow_hash >= hal_fst->max_entries)
+		trunc_hash &= hal_fst->hash_mask;
+	return trunc_hash;
+}
+qdf_export_symbol(hal_rx_get_hal_hash);
+
+/**
+ * hal_rx_insert_flow_entry() - Add a flow into the FST table
+ *
+ * @hal_fst: HAL Rx FST Handle
+ * @flow_hash: Flow hash computed from flow tuple
+ * @flow_tuple_info: Flow tuple used to compute the hash
+ * @flow_index: Hash index of the flow in the table when inserted successfully
+ *
+ * Return: Success if flow is inserted into the table, error otherwise
+ */
+QDF_STATUS
+hal_rx_insert_flow_entry(struct hal_rx_fst *fst, uint32_t flow_hash,
+			 void *flow_tuple_info, uint32_t *flow_idx)
+{
+	int i;
+	void *hal_fse;
+	uint32_t hal_hash;
+	struct hal_flow_tuple_info hal_tuple_info = { 0 };
+	QDF_STATUS status;
+
+	for (i = 0; i < fst->max_skid_length; i++) {
+		hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
+		hal_fse = (uint8_t *)fst->base_vaddr +
+			(hal_hash * HAL_RX_FST_ENTRY_SIZE);
+		status = hal_rx_flow_get_tuple_info(hal_fse, &hal_tuple_info);
+		if (status == QDF_STATUS_E_NOENT)
+			break;
+
+		/* Find the matching flow entry in HW FST */
+		if (!qdf_mem_cmp(&hal_tuple_info,
+				 flow_tuple_info,
+				 sizeof(struct hal_flow_tuple_info))) {
+			dp_err("Duplicate flow entry in FST %u at skid %u ",
+			       hal_hash, i);
+			return QDF_STATUS_E_EXISTS;
+		}
+	}
+	if (i == fst->max_skid_length) {
+		dp_err("Max skid length reached for hash %u", flow_hash);
+		return QDF_STATUS_E_RANGE;
+	}
+	*flow_idx = hal_hash;
+	dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
+		flow_hash, i, hal_fse, *flow_idx);
+
+	return QDF_STATUS_SUCCESS;
+}
+qdf_export_symbol(hal_rx_insert_flow_entry);
+
+/**
+ * hal_rx_find_flow_from_tuple() - Find a flow in the FST table
+ *
+ * @fst: HAL Rx FST Handle
+ * @flow_hash: Flow hash computed from flow tuple
+ * @flow_tuple_info: Flow tuple used to compute the hash
+ * @flow_index: Hash index of the flow in the table when found
+ *
+ * Return: Success if matching flow is found in the table, error otherwise
+ */
+QDF_STATUS
+hal_rx_find_flow_from_tuple(struct hal_rx_fst *fst, uint32_t flow_hash,
+			    void *flow_tuple_info, uint32_t *flow_idx)
+{
+	int i;
+	void *hal_fse;
+	uint32_t hal_hash;
+	struct hal_flow_tuple_info hal_tuple_info = { 0 };
+	QDF_STATUS status;
+
+	for (i = 0; i < fst->max_skid_length; i++) {
+		hal_hash = hal_rx_get_hal_hash(fst, (flow_hash + i));
+		hal_fse = (uint8_t *)fst->base_vaddr +
+			(hal_hash * HAL_RX_FST_ENTRY_SIZE);
+		status = hal_rx_flow_get_tuple_info(hal_fse, &hal_tuple_info);
+		if (status != QDF_STATUS_SUCCESS)
+			continue;
+
+		/* Find the matching flow entry in HW FST */
+		if (!qdf_mem_cmp(&hal_tuple_info,
+				 flow_tuple_info,
+				 sizeof(struct hal_flow_tuple_info))) {
+			break;
+		}
+	}
+
+	if (i == fst->max_skid_length) {
+		dp_err("Max skid length reached for hash %u", flow_hash);
+		return QDF_STATUS_E_RANGE;
+	}
+
+	*flow_idx = hal_hash;
+	dp_info("flow_hash = %u, skid_entry = %d, flow_addr = %pK flow_idx = %d",
+		flow_hash, i, hal_fse, *flow_idx);
+
+	return QDF_STATUS_SUCCESS;
+}
+qdf_export_symbol(hal_rx_find_flow_from_tuple);