|
@@ -21,6 +21,7 @@
|
|
|
#include "dp_internal.h"
|
|
|
#include <enet.h>
|
|
|
#include <linux/skbuff.h>
|
|
|
+#include "hif.h"
|
|
|
|
|
|
static void dp_rx_fisa_flush_flow_wrap(struct dp_fisa_rx_sw_ft *sw_ft);
|
|
|
|
|
@@ -234,6 +235,76 @@ dp_rx_fisa_setup_hw_fse(struct dp_rx_fst *fisa_hdl,
|
|
|
return hw_fse;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * dp_rx_fisa_acquire_ft_lock() - Acquire lock which protects SW FT entries
|
|
|
+ * @fisa_hdl: Handle to fisa context
|
|
|
+ * @reo_id: REO ID
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static inline void
|
|
|
+dp_rx_fisa_acquire_ft_lock(struct dp_rx_fst *fisa_hdl, uint8_t reo_id)
|
|
|
+{
|
|
|
+ if (fisa_hdl->flow_deletion_supported)
|
|
|
+ qdf_spin_lock_bh(&fisa_hdl->dp_rx_sw_ft_lock[reo_id]);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_rx_fisa_acquire_ft_lock() - Release lock which protects SW FT entries
|
|
|
+ * @fisa_hdl: Handle to fisa context
|
|
|
+ * @reo_id: REO ID
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static inline void
|
|
|
+dp_rx_fisa_release_ft_lock(struct dp_rx_fst *fisa_hdl, uint8_t reo_id)
|
|
|
+{
|
|
|
+ if (fisa_hdl->flow_deletion_supported)
|
|
|
+ qdf_spin_unlock_bh(&fisa_hdl->dp_rx_sw_ft_lock[reo_id]);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_rx_fisa_setup_cmem_fse() - Setup the flow search entry in HW CMEM
|
|
|
+ * @fisa_hdl: Handle to fisa context
|
|
|
+ * @hashed_flow_idx: Index to flow table
|
|
|
+ * @rx_flow_info: tuple to be populated in flow table
|
|
|
+ * @flow_steer_info: REO index to which flow to be steered
|
|
|
+ *
|
|
|
+ * Return: Offset to the FSE entry in CMEM
|
|
|
+ */
|
|
|
+static uint32_t
|
|
|
+dp_rx_fisa_setup_cmem_fse(struct dp_rx_fst *fisa_hdl, uint32_t hashed_flow_idx,
|
|
|
+ struct cdp_rx_flow_tuple_info *rx_flow_info,
|
|
|
+ uint32_t flow_steer_info)
|
|
|
+{
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_entry;
|
|
|
+ struct hal_rx_flow flow;
|
|
|
+
|
|
|
+ sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *)
|
|
|
+ fisa_hdl->base)[hashed_flow_idx]);
|
|
|
+ sw_ft_entry->metadata = ++fisa_hdl->meta_counter;
|
|
|
+
|
|
|
+ /* REO destination index starts from 1 */
|
|
|
+ flow.reo_destination_indication = flow_steer_info + 1;
|
|
|
+ flow.fse_metadata = sw_ft_entry->metadata;
|
|
|
+ flow.tuple_info.dest_ip_127_96 = rx_flow_info->dest_ip_127_96;
|
|
|
+ flow.tuple_info.dest_ip_95_64 = rx_flow_info->dest_ip_95_64;
|
|
|
+ flow.tuple_info.dest_ip_63_32 = rx_flow_info->dest_ip_63_32;
|
|
|
+ flow.tuple_info.dest_ip_31_0 = rx_flow_info->dest_ip_31_0;
|
|
|
+ flow.tuple_info.src_ip_127_96 = rx_flow_info->src_ip_127_96;
|
|
|
+ flow.tuple_info.src_ip_95_64 = rx_flow_info->src_ip_95_64;
|
|
|
+ flow.tuple_info.src_ip_63_32 = rx_flow_info->src_ip_63_32;
|
|
|
+ flow.tuple_info.src_ip_31_0 = rx_flow_info->src_ip_31_0;
|
|
|
+ flow.tuple_info.dest_port = rx_flow_info->dest_port;
|
|
|
+ flow.tuple_info.src_port = rx_flow_info->src_port;
|
|
|
+ flow.tuple_info.l4_protocol = rx_flow_info->l4_protocol;
|
|
|
+ flow.reo_destination_handler = HAL_RX_FSE_REO_DEST_FT;
|
|
|
+
|
|
|
+ return hal_rx_flow_setup_cmem_fse(fisa_hdl->soc_hdl->hal_soc,
|
|
|
+ fisa_hdl->cmem_ba, hashed_flow_idx,
|
|
|
+ &flow);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* dp_rx_fisa_update_sw_ft_entry() - Helper function to update few SW FT entry
|
|
|
* @sw_ft_entry: Pointer to softerware flow tabel entry
|
|
@@ -443,6 +514,377 @@ static bool is_flow_idx_valid(bool flow_invalid, bool flow_timeout)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_delete_flow() - Delete a flow from SW and HW FST, currently
|
|
|
+ * only applicable when FST is in CMEM
|
|
|
+ * @fisa_hdl: handle to FISA context
|
|
|
+ * @elem: details of the flow which is being added
|
|
|
+ * @hashed_flow_idx: hashed flow idx of the deleting flow
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static void
|
|
|
+dp_fisa_rx_delete_flow(struct dp_rx_fst *fisa_hdl,
|
|
|
+ struct dp_fisa_rx_fst_update_elem *elem,
|
|
|
+ uint32_t hashed_flow_idx)
|
|
|
+{
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_entry;
|
|
|
+ u8 reo_id;
|
|
|
+
|
|
|
+ sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *)
|
|
|
+ fisa_hdl->base)[hashed_flow_idx]);
|
|
|
+ reo_id = sw_ft_entry->napi_id;
|
|
|
+
|
|
|
+ dp_rx_fisa_acquire_ft_lock(fisa_hdl, reo_id);
|
|
|
+
|
|
|
+ /* Flush the flow before deletion */
|
|
|
+ dp_rx_fisa_flush_flow_wrap(sw_ft_entry);
|
|
|
+
|
|
|
+ memset(sw_ft_entry, 0, sizeof(*sw_ft_entry));
|
|
|
+
|
|
|
+ dp_rx_fisa_update_sw_ft_entry(sw_ft_entry, elem->flow_idx, elem->vdev,
|
|
|
+ fisa_hdl->soc_hdl, hashed_flow_idx);
|
|
|
+
|
|
|
+ /* Add HW FT entry */
|
|
|
+ sw_ft_entry->cmem_offset = dp_rx_fisa_setup_cmem_fse(
|
|
|
+ fisa_hdl, hashed_flow_idx,
|
|
|
+ &elem->flow_tuple_info, elem->reo_id);
|
|
|
+
|
|
|
+ sw_ft_entry->is_populated = true;
|
|
|
+ sw_ft_entry->napi_id = elem->reo_id;
|
|
|
+ qdf_mem_copy(&sw_ft_entry->rx_flow_tuple_info, &elem->flow_tuple_info,
|
|
|
+ sizeof(struct cdp_rx_flow_tuple_info));
|
|
|
+
|
|
|
+ sw_ft_entry->is_flow_tcp = elem->is_tcp_flow;
|
|
|
+ sw_ft_entry->is_flow_udp = elem->is_udp_flow;
|
|
|
+
|
|
|
+ dp_rx_fisa_release_ft_lock(fisa_hdl, reo_id);
|
|
|
+
|
|
|
+ fisa_hdl->add_flow_count++;
|
|
|
+ fisa_hdl->del_flow_count++;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_get_hw_ft_timestamp() - Get timestamp maintained in the HW FSE
|
|
|
+ * @fisa_hdl: handle to FISA context
|
|
|
+ * @hashed_flow_idx: hashed idx of the flow
|
|
|
+ *
|
|
|
+ * Return: Timestamp
|
|
|
+ */
|
|
|
+static uint32_t
|
|
|
+dp_fisa_rx_get_hw_ft_timestamp(struct dp_rx_fst *fisa_hdl,
|
|
|
+ uint32_t hashed_flow_idx)
|
|
|
+{
|
|
|
+ hal_soc_handle_t hal_soc_hdl = fisa_hdl->soc_hdl->hal_soc;
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_entry;
|
|
|
+
|
|
|
+ sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *)
|
|
|
+ fisa_hdl->base)[hashed_flow_idx]);
|
|
|
+
|
|
|
+ if (fisa_hdl->soc_hdl->fst_in_cmem)
|
|
|
+ return hal_rx_flow_get_cmem_fse_timestamp(
|
|
|
+ hal_soc_hdl, sw_ft_entry->cmem_offset);
|
|
|
+
|
|
|
+ return ((struct rx_flow_search_entry *)sw_ft_entry->hw_fse)->timestamp;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_fst_update() - Core logic which helps in Addition/Deletion
|
|
|
+ * of flows
|
|
|
+ * into/from SW & HW FST
|
|
|
+ * @fisa_hdl: handle to FISA context
|
|
|
+ * @elem: details of the flow which is being added
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static void dp_fisa_rx_fst_update(struct dp_rx_fst *fisa_hdl,
|
|
|
+ struct dp_fisa_rx_fst_update_elem *elem)
|
|
|
+{
|
|
|
+ struct cdp_rx_flow_tuple_info *rx_flow_tuple_info;
|
|
|
+ uint32_t skid_count = 0, max_skid_length;
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_entry;
|
|
|
+ bool is_fst_updated = false;
|
|
|
+ uint32_t hashed_flow_idx;
|
|
|
+ uint32_t flow_hash;
|
|
|
+ uint32_t lru_ft_entry_time = 0xffffffff;
|
|
|
+ uint32_t lru_ft_entry_idx = 0;
|
|
|
+ uint32_t timestamp;
|
|
|
+
|
|
|
+ /* Get the hash from TLV
|
|
|
+ * FSE FT Toeplitz hash is same Common parser hash available in TLV
|
|
|
+ * common parser toeplitz hash is same as FSE toeplitz hash as
|
|
|
+ * toeplitz key is same.
|
|
|
+ */
|
|
|
+ flow_hash = elem->flow_idx;
|
|
|
+ hashed_flow_idx = flow_hash & fisa_hdl->hash_mask;
|
|
|
+ max_skid_length = fisa_hdl->max_skid_length;
|
|
|
+ rx_flow_tuple_info = &elem->flow_tuple_info;
|
|
|
+
|
|
|
+ dp_fisa_debug("flow_hash 0x%x hashed_flow_idx 0x%x", flow_hash,
|
|
|
+ hashed_flow_idx);
|
|
|
+ dp_fisa_debug("max_skid_length 0x%x", max_skid_length);
|
|
|
+
|
|
|
+ do {
|
|
|
+ sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *)
|
|
|
+ fisa_hdl->base)[hashed_flow_idx]);
|
|
|
+ if (!sw_ft_entry->is_populated) {
|
|
|
+ /* Add SW FT entry */
|
|
|
+ dp_rx_fisa_update_sw_ft_entry(sw_ft_entry,
|
|
|
+ flow_hash, elem->vdev,
|
|
|
+ fisa_hdl->soc_hdl,
|
|
|
+ hashed_flow_idx);
|
|
|
+
|
|
|
+ /* Add HW FT entry */
|
|
|
+ sw_ft_entry->cmem_offset =
|
|
|
+ dp_rx_fisa_setup_cmem_fse(fisa_hdl,
|
|
|
+ hashed_flow_idx,
|
|
|
+ rx_flow_tuple_info,
|
|
|
+ elem->reo_id);
|
|
|
+ sw_ft_entry->is_populated = true;
|
|
|
+ sw_ft_entry->napi_id = elem->reo_id;
|
|
|
+ qdf_mem_copy(&sw_ft_entry->rx_flow_tuple_info,
|
|
|
+ rx_flow_tuple_info,
|
|
|
+ sizeof(struct cdp_rx_flow_tuple_info));
|
|
|
+
|
|
|
+ sw_ft_entry->is_flow_tcp = elem->is_tcp_flow;
|
|
|
+ sw_ft_entry->is_flow_udp = elem->is_udp_flow;
|
|
|
+
|
|
|
+ is_fst_updated = true;
|
|
|
+ fisa_hdl->add_flow_count++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* else */
|
|
|
+ /* hash collision move to the next FT entry */
|
|
|
+ dp_fisa_debug("Hash collision %d",
|
|
|
+ fisa_hdl->hash_collision_cnt);
|
|
|
+ fisa_hdl->hash_collision_cnt++;
|
|
|
+
|
|
|
+ timestamp = dp_fisa_rx_get_hw_ft_timestamp(fisa_hdl,
|
|
|
+ hashed_flow_idx);
|
|
|
+ if (timestamp < lru_ft_entry_time) {
|
|
|
+ lru_ft_entry_time = timestamp;
|
|
|
+ lru_ft_entry_idx = hashed_flow_idx;
|
|
|
+ }
|
|
|
+ skid_count++;
|
|
|
+ hashed_flow_idx++;
|
|
|
+ hashed_flow_idx &= fisa_hdl->hash_mask;
|
|
|
+ } while (skid_count <= max_skid_length);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * if (skid_count > max_skid_length)
|
|
|
+ * Remove LRU flow from HW FT
|
|
|
+ * Remove LRU flow from SW FT
|
|
|
+ */
|
|
|
+ if (skid_count > max_skid_length) {
|
|
|
+ dp_fisa_debug("Max skid length reached flow cannot be added, evict exiting flow");
|
|
|
+ dp_fisa_rx_delete_flow(fisa_hdl, elem, lru_ft_entry_idx);
|
|
|
+ is_fst_updated = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Send HTT cache invalidation command to firmware to
|
|
|
+ * reflect the flow update
|
|
|
+ */
|
|
|
+ if (is_fst_updated &&
|
|
|
+ (qdf_atomic_inc_return(&fisa_hdl->fse_cache_flush_posted) == 1)) {
|
|
|
+ /* return 1 after increment implies FSE cache flush message
|
|
|
+ * already posted. so start restart the timer
|
|
|
+ */
|
|
|
+ qdf_timer_start(&fisa_hdl->fse_cache_flush_timer,
|
|
|
+ FSE_CACHE_FLUSH_TIME_OUT);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_fst_update_work() - Work functions for FST updates
|
|
|
+ * @arg: argument passed to the work function
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void dp_fisa_rx_fst_update_work(void *arg)
|
|
|
+{
|
|
|
+ struct dp_fisa_rx_fst_update_elem *elem;
|
|
|
+ struct dp_rx_fst *fisa_hdl = arg;
|
|
|
+ qdf_list_node_t *node;
|
|
|
+ hal_soc_handle_t hal_soc_hdl = fisa_hdl->soc_hdl->hal_soc;
|
|
|
+
|
|
|
+ if (hif_force_wake_request(((struct hal_soc *)hal_soc_hdl)->hif_handle)) {
|
|
|
+ dp_err("Wake up request failed");
|
|
|
+ qdf_check_state_before_panic();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock);
|
|
|
+ while (qdf_list_peek_front(&fisa_hdl->fst_update_list, &node) ==
|
|
|
+ QDF_STATUS_SUCCESS) {
|
|
|
+ elem = (struct dp_fisa_rx_fst_update_elem *)node;
|
|
|
+ dp_fisa_rx_fst_update(fisa_hdl, elem);
|
|
|
+ qdf_list_remove_front(&fisa_hdl->fst_update_list, &node);
|
|
|
+ qdf_mem_free(elem);
|
|
|
+ }
|
|
|
+ qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock);
|
|
|
+
|
|
|
+ if (hif_force_wake_release(((struct hal_soc *)hal_soc_hdl)->hif_handle)) {
|
|
|
+ dp_err("Wake up release failed");
|
|
|
+ qdf_check_state_before_panic();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_is_fst_work_queued() - Check if work is already queued for
|
|
|
+ * the flow
|
|
|
+ * @fisa_hdl: handle to FISA context
|
|
|
+ * @flow_idx: Flow index
|
|
|
+ *
|
|
|
+ * Return: True/False
|
|
|
+ */
|
|
|
+static inline bool
|
|
|
+dp_fisa_rx_is_fst_work_queued(struct dp_rx_fst *fisa_hdl, uint32_t flow_idx)
|
|
|
+{
|
|
|
+ struct dp_fisa_rx_fst_update_elem *elem;
|
|
|
+ qdf_list_node_t *cur_node, *next_node;
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = qdf_list_peek_front(&fisa_hdl->fst_update_list, &cur_node);
|
|
|
+ if (status == QDF_STATUS_E_EMPTY)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ do {
|
|
|
+ elem = (struct dp_fisa_rx_fst_update_elem *)cur_node;
|
|
|
+ if (elem->flow_idx == flow_idx)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ status = qdf_list_peek_next(&fisa_hdl->fst_update_list,
|
|
|
+ cur_node, &next_node);
|
|
|
+ cur_node = next_node;
|
|
|
+ } while (status == QDF_STATUS_SUCCESS);
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_queue_fst_update_work() - Queue FST update work
|
|
|
+ * @fisa_hdl: Handle to FISA context
|
|
|
+ * @flow_idx: Flow index
|
|
|
+ * @nbuf: Received RX packet
|
|
|
+ * @vdev: DP vdev handle
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static void *
|
|
|
+dp_fisa_rx_queue_fst_update_work(struct dp_rx_fst *fisa_hdl, uint32_t flow_idx,
|
|
|
+ qdf_nbuf_t nbuf, struct dp_vdev *vdev)
|
|
|
+{
|
|
|
+ hal_soc_handle_t hal_soc_hdl = fisa_hdl->soc_hdl->hal_soc;
|
|
|
+ struct cdp_rx_flow_tuple_info flow_tuple_info;
|
|
|
+ bool is_flow_tcp, is_flow_udp, is_flow_ipv6;
|
|
|
+ uint8_t *rx_tlv_hdr = qdf_nbuf_data(nbuf);
|
|
|
+ struct dp_fisa_rx_fst_update_elem *elem;
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_entry;
|
|
|
+ uint32_t hashed_flow_idx;
|
|
|
+ bool found;
|
|
|
+
|
|
|
+ is_flow_tcp = HAL_RX_TLV_GET_TCP_PROTO(rx_tlv_hdr);
|
|
|
+ is_flow_udp = HAL_RX_TLV_GET_UDP_PROTO(rx_tlv_hdr);
|
|
|
+ is_flow_ipv6 = HAL_RX_TLV_GET_IPV6(rx_tlv_hdr);
|
|
|
+
|
|
|
+ if (is_flow_ipv6 || !(is_flow_tcp || is_flow_udp)) {
|
|
|
+ dp_fisa_debug("Not UDP or TCP IPV4 flow");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock);
|
|
|
+ found = dp_fisa_rx_is_fst_work_queued(fisa_hdl, flow_idx);
|
|
|
+ qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock);
|
|
|
+ if (found)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ hashed_flow_idx = flow_idx & fisa_hdl->hash_mask;
|
|
|
+ sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *)
|
|
|
+ fisa_hdl->base)[hashed_flow_idx]);
|
|
|
+
|
|
|
+ get_flow_tuple_from_nbuf(hal_soc_hdl, &flow_tuple_info,
|
|
|
+ nbuf, rx_tlv_hdr);
|
|
|
+
|
|
|
+ if (sw_ft_entry->is_populated && is_same_flow(
|
|
|
+ &sw_ft_entry->rx_flow_tuple_info, &flow_tuple_info))
|
|
|
+ return sw_ft_entry;
|
|
|
+
|
|
|
+ elem = qdf_mem_malloc(sizeof(*elem));
|
|
|
+ if (!elem) {
|
|
|
+ dp_fisa_debug("failed to allocate memory for FST update");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ qdf_mem_copy(&elem->flow_tuple_info, &flow_tuple_info,
|
|
|
+ sizeof(struct cdp_rx_flow_tuple_info));
|
|
|
+ elem->flow_idx = flow_idx;
|
|
|
+ elem->is_tcp_flow = is_flow_tcp;
|
|
|
+ elem->is_udp_flow = is_flow_udp;
|
|
|
+ elem->reo_id = QDF_NBUF_CB_RX_CTX_ID(nbuf);
|
|
|
+ elem->vdev = vdev;
|
|
|
+
|
|
|
+ qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock);
|
|
|
+ qdf_list_insert_back(&fisa_hdl->fst_update_list, &elem->node);
|
|
|
+ qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock);
|
|
|
+
|
|
|
+ qdf_queue_work(fisa_hdl->soc_hdl->osdev, fisa_hdl->fst_update_wq,
|
|
|
+ &fisa_hdl->fst_update_work);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dp_fisa_rx_get_sw_ft_entry() - Get SW FT entry for the flow
|
|
|
+ * @fisa_hdl: Handle to FISA context
|
|
|
+ * @nbuf: Received RX packet
|
|
|
+ * @flow_idx: Flow index
|
|
|
+ * @vdev: handle to DP vdev
|
|
|
+ *
|
|
|
+ * Return: SW FT entry
|
|
|
+ */
|
|
|
+static inline struct dp_fisa_rx_sw_ft *
|
|
|
+dp_fisa_rx_get_sw_ft_entry(struct dp_rx_fst *fisa_hdl, qdf_nbuf_t nbuf,
|
|
|
+ uint32_t flow_idx, struct dp_vdev *vdev)
|
|
|
+{
|
|
|
+ hal_soc_handle_t hal_soc_hdl = fisa_hdl->soc_hdl->hal_soc;
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_entry = NULL;
|
|
|
+ struct dp_fisa_rx_sw_ft *sw_ft_base;
|
|
|
+ uint32_t fse_metadata;
|
|
|
+ uint8_t *rx_tlv_hdr;
|
|
|
+
|
|
|
+ sw_ft_base = (struct dp_fisa_rx_sw_ft *)fisa_hdl->base;
|
|
|
+ rx_tlv_hdr = qdf_nbuf_data(nbuf);
|
|
|
+
|
|
|
+ if (qdf_unlikely(flow_idx >= fisa_hdl->max_entries)) {
|
|
|
+ dp_info("flow_idx is invalid 0x%x", flow_idx);
|
|
|
+ hal_rx_dump_pkt_tlvs(hal_soc_hdl, rx_tlv_hdr,
|
|
|
+ QDF_TRACE_LEVEL_INFO_HIGH);
|
|
|
+ DP_STATS_INC(fisa_hdl, invalid_flow_index, 1);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ sw_ft_entry = &sw_ft_base[flow_idx];
|
|
|
+
|
|
|
+ if (!fisa_hdl->flow_deletion_supported) {
|
|
|
+ sw_ft_entry->vdev = vdev;
|
|
|
+ return sw_ft_entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* When a flow is deleted, there could be some packets of that flow
|
|
|
+ * with valid flow_idx in the REO queue and arrive at a later time,
|
|
|
+ * compare the metadata for such packets before returning the SW FT
|
|
|
+ * entry to avoid packets getting aggregated with the wrong flow.
|
|
|
+ */
|
|
|
+ fse_metadata = hal_rx_msdu_fse_metadata_get(hal_soc_hdl, rx_tlv_hdr);
|
|
|
+ if (fisa_hdl->del_flow_count && fse_metadata != sw_ft_entry->metadata)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ sw_ft_entry->vdev = vdev;
|
|
|
+ return sw_ft_entry;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* dp_rx_get_fisa_flow() - Get FT entry corresponding to incoming nbuf
|
|
|
* @fisa_hdl: handle to FISA context
|
|
@@ -459,8 +901,6 @@ dp_rx_get_fisa_flow(struct dp_rx_fst *fisa_hdl, struct dp_vdev *vdev,
|
|
|
uint32_t flow_idx;
|
|
|
bool flow_invalid, flow_timeout, flow_idx_valid;
|
|
|
struct dp_fisa_rx_sw_ft *sw_ft_entry = NULL;
|
|
|
- struct dp_fisa_rx_sw_ft *sw_ft_base = (struct dp_fisa_rx_sw_ft *)
|
|
|
- fisa_hdl->base;
|
|
|
hal_soc_handle_t hal_soc_hdl = fisa_hdl->soc_hdl->hal_soc;
|
|
|
|
|
|
if (QDF_NBUF_CB_RX_TCP_PROTO(nbuf))
|
|
@@ -475,21 +915,16 @@ dp_rx_get_fisa_flow(struct dp_rx_fst *fisa_hdl, struct dp_vdev *vdev,
|
|
|
|
|
|
flow_idx_valid = is_flow_idx_valid(flow_invalid, flow_timeout);
|
|
|
if (flow_idx_valid) {
|
|
|
- /* If flow index is invalid, fail to get flow */
|
|
|
- if (qdf_unlikely(flow_idx >= fisa_hdl->max_entries)) {
|
|
|
- dp_info("flow_idx is invalid 0x%x", flow_idx);
|
|
|
- hal_rx_dump_pkt_tlvs(hal_soc_hdl, rx_tlv_hdr,
|
|
|
- QDF_TRACE_LEVEL_INFO_HIGH);
|
|
|
- DP_STATS_INC(fisa_hdl, invalid_flow_index, 1);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- sw_ft_entry = &sw_ft_base[flow_idx];
|
|
|
- sw_ft_entry->vdev = vdev;
|
|
|
-
|
|
|
+ sw_ft_entry = dp_fisa_rx_get_sw_ft_entry(fisa_hdl, nbuf,
|
|
|
+ flow_idx, vdev);
|
|
|
return sw_ft_entry;
|
|
|
}
|
|
|
|
|
|
/* else new flow, add entry to FT */
|
|
|
+ if (fisa_hdl->soc_hdl->fst_in_cmem)
|
|
|
+ return dp_fisa_rx_queue_fst_update_work(fisa_hdl, flow_idx,
|
|
|
+ nbuf, vdev);
|
|
|
+
|
|
|
sw_ft_entry = dp_rx_fisa_add_ft_entry(fisa_hdl, flow_idx, nbuf, vdev,
|
|
|
rx_tlv_hdr);
|
|
|
|
|
@@ -1006,6 +1441,8 @@ static int dp_add_nbuf_to_fisa_flow(struct dp_rx_fst *fisa_hdl,
|
|
|
hal_aggr_count = hal_rx_get_fisa_flow_agg_count(hal_soc_hdl,
|
|
|
rx_tlv_hdr);
|
|
|
|
|
|
+ dp_rx_fisa_acquire_ft_lock(fisa_hdl, fisa_flow->napi_id);
|
|
|
+
|
|
|
if (!flow_aggr_cont) {
|
|
|
/* Start of new aggregation for the flow
|
|
|
* Flush previous aggregates for this flow
|
|
@@ -1113,10 +1550,12 @@ static int dp_add_nbuf_to_fisa_flow(struct dp_rx_fst *fisa_hdl,
|
|
|
dp_rx_fisa_aggr_tcp(fisa_hdl, fisa_flow, nbuf);
|
|
|
}
|
|
|
|
|
|
+ dp_rx_fisa_release_ft_lock(fisa_hdl, fisa_flow->napi_id);
|
|
|
return FISA_AGGR_DONE;
|
|
|
|
|
|
invalid_fisa_assist:
|
|
|
/* Not eligible aggregation deliver frame without FISA */
|
|
|
+ dp_rx_fisa_release_ft_lock(fisa_hdl, fisa_flow->napi_id);
|
|
|
return FISA_AGGR_NOT_ELIGIBLE;
|
|
|
}
|
|
|
|
|
@@ -1156,6 +1595,7 @@ QDF_STATUS dp_rx_fisa_flush_by_vdev_ctx_id(struct dp_soc *soc,
|
|
|
int ft_size = fisa_hdl->max_entries;
|
|
|
int i;
|
|
|
|
|
|
+ dp_rx_fisa_acquire_ft_lock(fisa_hdl, rx_ctx_id);
|
|
|
for (i = 0; i < ft_size; i++) {
|
|
|
if (sw_ft_entry[i].is_populated &&
|
|
|
vdev == sw_ft_entry[i].vdev &&
|
|
@@ -1165,6 +1605,7 @@ QDF_STATUS dp_rx_fisa_flush_by_vdev_ctx_id(struct dp_soc *soc,
|
|
|
dp_rx_fisa_flush_flow_wrap(&sw_ft_entry[i]);
|
|
|
}
|
|
|
}
|
|
|
+ dp_rx_fisa_release_ft_lock(fisa_hdl, rx_ctx_id);
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
@@ -1249,8 +1690,13 @@ QDF_STATUS dp_fisa_rx(struct dp_soc *soc, struct dp_vdev *vdev,
|
|
|
*/
|
|
|
if (qdf_unlikely(qdf_nbuf_get_ext_list(head_nbuf))) {
|
|
|
dp_fisa_debug("Fragmented skb, will not be FISAed");
|
|
|
- if (fisa_flow)
|
|
|
+ if (fisa_flow) {
|
|
|
+ dp_rx_fisa_acquire_ft_lock(dp_fisa_rx_hdl,
|
|
|
+ fisa_flow->napi_id);
|
|
|
dp_rx_fisa_flush_flow(vdev, fisa_flow);
|
|
|
+ dp_rx_fisa_release_ft_lock(dp_fisa_rx_hdl,
|
|
|
+ fisa_flow->napi_id);
|
|
|
+ }
|
|
|
goto pull_nbuf;
|
|
|
}
|
|
|
|
|
@@ -1344,6 +1790,7 @@ QDF_STATUS dp_rx_fisa_flush_by_ctx_id(struct dp_soc *soc, int napi_id)
|
|
|
int ft_size = fisa_hdl->max_entries;
|
|
|
int i;
|
|
|
|
|
|
+ dp_rx_fisa_acquire_ft_lock(fisa_hdl, napi_id);
|
|
|
for (i = 0; i < ft_size; i++) {
|
|
|
if (sw_ft_entry[i].napi_id == napi_id &&
|
|
|
sw_ft_entry[i].is_populated) {
|
|
@@ -1352,6 +1799,7 @@ QDF_STATUS dp_rx_fisa_flush_by_ctx_id(struct dp_soc *soc, int napi_id)
|
|
|
dp_rx_fisa_flush_flow_wrap(&sw_ft_entry[i]);
|
|
|
}
|
|
|
}
|
|
|
+ dp_rx_fisa_release_ft_lock(fisa_hdl, napi_id);
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
@@ -1372,11 +1820,14 @@ QDF_STATUS dp_rx_fisa_flush_by_vdev_id(struct dp_soc *soc, uint8_t vdev_id)
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < ft_size; i++) {
|
|
|
+ dp_rx_fisa_acquire_ft_lock(fisa_hdl, sw_ft_entry[i].napi_id);
|
|
|
if (vdev == sw_ft_entry[i].vdev) {
|
|
|
dp_fisa_debug("flushing %d %pk vdev %pK", i,
|
|
|
&sw_ft_entry[i], vdev);
|
|
|
+
|
|
|
dp_rx_fisa_flush_flow_wrap(&sw_ft_entry[i]);
|
|
|
}
|
|
|
+ dp_rx_fisa_release_ft_lock(fisa_hdl, sw_ft_entry[i].napi_id);
|
|
|
}
|
|
|
dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX);
|
|
|
|