Browse Source

qcacmn: Enable PN check for 2K-jump and OOR frames

Currently the EAPOL/ARP/DHCP frames arriving as 2K-jump
or out-of-order frmaes are being delivered to the network
stack, without checking for the packet-number sequence.

WCN7850 has hardware support to provide the packet number
of the previous successful re-ordered packet from hardware.
Use this feature to check if the packet-number are in proper
sequence for these EAPOL/ARP/DHCP packets arriving as 2k-jump
or out-of-order packets before submitting it to the network
stack.

Change-Id: I1078452afce4bc00b2509436295e5bd80000feb4
CRs-Fixed: 2965086
Rakesh Pillai 4 years ago
parent
commit
5d44eac10a

+ 2 - 0
dp/wifi3.0/dp_main.c

@@ -13393,6 +13393,8 @@ void *dp_soc_init(struct dp_soc *soc, HTC_HANDLE htc_handle,
 
 	hal_reo_set_err_dst_remap(soc->hal_soc);
 
+	soc->features.pn_in_reo_dest = hal_reo_enable_pn_in_dest(soc->hal_soc);
+
 	qdf_atomic_set(&soc->cmn_init_done, 1);
 
 	qdf_nbuf_queue_init(&soc->htt_stats.msg);

+ 86 - 3
dp/wifi3.0/dp_rx_err.c

@@ -510,6 +510,32 @@ free_nbuf:
 	qdf_nbuf_free(nbuf);
 }
 
+/**
+ * dp_rx_err_nbuf_pn_check() - Check if the PN number of this current packet
+ *				is a monotonous increment of packet number
+ *				from the previous successfully re-ordered
+ *				frame.
+ * @soc: Datapath SOC handle
+ * @ring_desc: REO ring descriptor
+ * @nbuf: Current packet
+ *
+ * Return: QDF_STATUS_SUCCESS, if the pn check passes, else QDF_STATUS_E_FAILURE
+ */
+static inline QDF_STATUS
+dp_rx_err_nbuf_pn_check(struct dp_soc *soc, hal_ring_desc_t ring_desc,
+			qdf_nbuf_t nbuf)
+{
+	uint64_t prev_pn, curr_pn;
+
+	hal_rx_reo_prev_pn_get(soc->hal_soc, ring_desc, &prev_pn);
+	hal_rx_tlv_get_pn_num(soc->hal_soc, qdf_nbuf_data(nbuf), &curr_pn);
+
+	if (curr_pn > prev_pn)
+		return QDF_STATUS_SUCCESS;
+
+	return QDF_STATUS_E_FAILURE;
+}
+
 /**
  * dp_rx_reo_err_entry_process() - Handles for REO error entry processing
  *
@@ -551,6 +577,7 @@ dp_rx_reo_err_entry_process(struct dp_soc *soc,
 	qdf_nbuf_t head_nbuf = NULL;
 	qdf_nbuf_t tail_nbuf = NULL;
 	uint16_t msdu_processed = 0;
+	QDF_STATUS status;
 	bool ret;
 
 	peer_id = DP_PEER_METADATA_PEER_ID_GET(
@@ -615,6 +642,22 @@ more_msdu_link_desc:
 			DP_STATS_INC(soc, rx.err.reo_err_oor_sg_count, 1);
 		}
 
+		if (soc->features.pn_in_reo_dest) {
+			status = dp_rx_err_nbuf_pn_check(soc, ring_desc, nbuf);
+			if (QDF_IS_STATUS_ERROR(status)) {
+				DP_STATS_INC(soc, rx.err.pn_in_dest_check_fail,
+					     1);
+				qdf_nbuf_free(nbuf);
+				goto process_next_msdu;
+			}
+
+			hal_rx_tlv_populate_mpdu_desc_info(soc->hal_soc,
+							   qdf_nbuf_data(nbuf),
+							   mpdu_desc_info);
+			peer_id = DP_PEER_METADATA_PEER_ID_GET(
+					mpdu_desc_info->peer_meta_data);
+		}
+
 		switch (err_code) {
 		case HAL_REO_ERR_REGULAR_FRAME_2K_JUMP:
 			/*
@@ -1948,6 +1991,27 @@ static int dp_rx_err_exception(struct dp_soc *soc, hal_ring_desc_t ring_desc)
 }
 #endif /* HANDLE_RX_REROUTE_ERR */
 
+/**
+ * dp_rx_err_is_pn_check_needed() - Check if the packet number check is needed
+ *				for this frame received in REO error ring.
+ * @soc: Datapath SOC handle
+ * @error: REO error detected or not
+ * @error_code: Error code in case of REO error
+ *
+ * Return: true if pn check if needed in software,
+ *	false, if pn check if not needed.
+ */
+static inline bool
+dp_rx_err_is_pn_check_needed(struct dp_soc *soc, uint8_t error,
+			     uint32_t error_code)
+{
+	return (soc->features.pn_in_reo_dest &&
+		(error == HAL_REO_ERROR_DETECTED &&
+		 (hal_rx_reo_is_2k_jump(error_code) ||
+		  hal_rx_reo_is_oor_error(error_code) ||
+		  hal_rx_reo_is_bar_oor_2k_jump(error_code))));
+}
+
 uint32_t
 dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 		  hal_ring_handle_t hal_ring_hdl, uint32_t quota)
@@ -1972,6 +2036,7 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 	QDF_STATUS status;
 	bool ret;
 	uint32_t error_code = 0;
+	bool sw_pn_check_needed;
 
 	/* Debug -- Remove later */
 	qdf_assert(soc && hal_ring_hdl);
@@ -2006,10 +2071,23 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 			error_code = hal_rx_get_reo_error_code(hal_soc,
 							       ring_desc);
 
-		/* Get the MPDU DESC info */
-		hal_rx_mpdu_desc_info_get(hal_soc, ring_desc, &mpdu_desc_info);
+		qdf_mem_set(&mpdu_desc_info, sizeof(mpdu_desc_info), 0);
+		sw_pn_check_needed = dp_rx_err_is_pn_check_needed(soc,
+								  err_status,
+								  error_code);
+		if (!sw_pn_check_needed) {
+			/*
+			 * MPDU desc info will be present in the REO desc
+			 * only in the below scenarios
+			 * 1) pn_in_dest_disabled:  always
+			 * 2) pn_in_dest enabled: All cases except 2k-jup
+			 *			and OOR errors
+			 */
+			hal_rx_mpdu_desc_info_get(hal_soc, ring_desc,
+						  &mpdu_desc_info);
+		}
 
-		if (mpdu_desc_info.msdu_count == 0)
+		if (HAL_RX_REO_DESC_MSDU_COUNT_GET(ring_desc) == 0)
 			goto next_entry;
 
 		/*
@@ -2074,6 +2152,10 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 
 		mac_id = rx_desc->pool_id;
 
+		if (sw_pn_check_needed) {
+			goto process_oor_2k_jump;
+		}
+
 		if (mpdu_desc_info.bar_frame) {
 			qdf_assert_always(mpdu_desc_info.msdu_count == 1);
 
@@ -2158,6 +2240,7 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 			goto next_entry;
 		}
 
+process_oor_2k_jump:
 		if (hal_rx_reo_is_2k_jump(error_code)) {
 			/* TOD0 */
 			DP_STATS_INC(soc,

+ 5 - 0
dp/wifi3.0/dp_stats.c

@@ -6040,6 +6040,8 @@ void dp_txrx_path_stats(struct dp_soc *soc)
 			       pdev->soc->stats.rx.err.ipa_smmu_unmap_dup);
 		DP_PRINT_STATS("Rx ipa smmu unmap no pipes: %d",
 			       pdev->soc->stats.rx.err.ipa_unmap_no_pipe);
+		DP_PRINT_STATS("PN-in-Dest error frame pn-check fail: %d",
+			       soc->stats.rx.err.pn_in_dest_check_fail);
 
 		DP_PRINT_STATS("Reo Statistics");
 		DP_PRINT_STATS("near_full: %u ", soc->stats.rx.near_full);
@@ -6675,6 +6677,9 @@ dp_print_soc_rx_stats(struct dp_soc *soc)
 	DP_PRINT_STATS("bar handle update fail count: %d",
 		       soc->stats.rx.err.bar_handle_fail_count);
 
+	DP_PRINT_STATS("PN-in-Dest error frame pn-check fail: %d",
+		       soc->stats.rx.err.pn_in_dest_check_fail);
+
 	for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) {
 		index += qdf_snprint(&rxdma_error[index],
 				DP_RXDMA_ERR_LENGTH - index,

+ 13 - 0
dp/wifi3.0/dp_types.h

@@ -1084,6 +1084,8 @@ struct dp_soc_stats {
 			uint32_t bar_handle_fail_count;
 			/* EAPOL drop count in intrabss scenario */
 			uint32_t intrabss_eapol_drop;
+			/* PN check failed for 2K-jump or OOR error */
+			uint32_t pn_in_dest_check_fail;
 			/* MSDU len err count */
 			uint32_t msdu_len_err;
 		} err;
@@ -1627,6 +1629,14 @@ struct dp_arch_ops {
 						 int *max_reap_limit);
 };
 
+/**
+ * struct dp_soc_features: Data structure holding the SOC level feature flags.
+ * @pn_in_reo_dest: PN provided by hardware in the REO destination ring.
+ */
+struct dp_soc_features {
+	uint8_t pn_in_reo_dest;
+};
+
 /* SOC level structure for data path */
 struct dp_soc {
 	/**
@@ -2103,6 +2113,9 @@ struct dp_soc {
 	uint64_t cmem_base;
 	/* CMEM size in bytes */
 	uint64_t cmem_size;
+
+	/* SOC level feature flags */
+	struct dp_soc_features features;
 };
 
 #ifdef IPA_OFFLOAD

+ 19 - 0
hal/wifi3.0/hal_api.h

@@ -2773,6 +2773,25 @@ static inline void hal_reo_set_err_dst_remap(hal_soc_handle_t hal_soc_hdl)
 		hal_soc->ops->hal_reo_set_err_dst_remap(hal_soc);
 }
 
+/**
+ * hal_reo_enable_pn_in_dest() - Subscribe for previous PN for 2k-jump or
+ *			OOR error frames
+ * @hal_soc_hdl: Opaque HAL soc handle
+ *
+ * Return: true if feature is enabled,
+ *	false, otherwise.
+ */
+static inline uint8_t
+hal_reo_enable_pn_in_dest(hal_soc_handle_t hal_soc_hdl)
+{
+	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
+
+	if (hal_soc->ops->hal_reo_enable_pn_in_dest)
+		return hal_soc->ops->hal_reo_enable_pn_in_dest(hal_soc);
+
+	return 0;
+}
+
 #ifdef GENERIC_SHADOW_REGISTER_ACCESS_ENABLE
 
 /**

+ 4 - 0
hal/wifi3.0/hal_internal.h

@@ -716,6 +716,7 @@ struct hal_hw_txrx_ops {
 	qdf_iomem_t (*hal_get_window_address)(struct hal_soc *hal_soc,
 					      qdf_iomem_t addr);
 	void (*hal_reo_set_err_dst_remap)(void *hal_soc);
+	uint8_t (*hal_reo_enable_pn_in_dest)(void *hal_soc);
 	void (*hal_reo_qdesc_setup)(hal_soc_handle_t hal_soc_hdl, int tid,
 				    uint32_t ba_window_size,
 				    uint32_t start_seq, void *hw_qdesc_vaddr,
@@ -904,6 +905,7 @@ struct hal_hw_txrx_ops {
 	uint32_t (*hal_rx_tlv_mic_err_get)(uint8_t *buf);
 	uint32_t (*hal_rx_tlv_get_pkt_type)(uint8_t *buf);
 	void (*hal_rx_tlv_get_pn_num)(uint8_t *buf, uint64_t *pn_num);
+	void (*hal_rx_reo_prev_pn_get)(void *ring_desc, uint64_t *prev_pn);
 	uint8_t * (*hal_rx_pkt_hdr_get)(uint8_t *buf);
 	uint32_t (*hal_rx_msdu_reo_dst_ind_get)(hal_soc_handle_t hal_soc_hdl,
 						void *msdu_link_desc);
@@ -958,6 +960,8 @@ struct hal_hw_txrx_ops {
 					      uint8_t *priv_data,
 					      uint32_t len);
 	void (*hal_rx_tlv_msdu_len_set)(uint8_t *buf, uint32_t len);
+	void (*hal_rx_tlv_populate_mpdu_desc_info)(uint8_t *buf,
+						   void *mpdu_desc_info_hdl);
 
 	/* REO CMD and STATUS */
 	int (*hal_reo_send_cmd)(hal_soc_handle_t hal_soc_hdl,

+ 63 - 0
hal/wifi3.0/hal_rx.h

@@ -251,6 +251,16 @@ enum hal_rx_mpdu_desc_flags {
 #define HAL_RX_BUF_RBM_SW5_BM(sw0_bm_id)	(sw0_bm_id + 5)
 #define HAL_RX_BUF_RBM_SW6_BM(sw0_bm_id)	(sw0_bm_id + 6)
 
+#define HAL_REO_DESTINATION_RING_MSDU_COUNT_OFFSET	0x8
+#define HAL_REO_DESTINATION_RING_MSDU_COUNT_LSB		0
+#define HAL_REO_DESTINATION_RING_MSDU_COUNT_MASK	0x000000ff
+
+#define HAL_RX_REO_DESC_MSDU_COUNT_GET(reo_desc)	\
+	(_HAL_MS((*_OFFSET_TO_WORD_PTR(reo_desc,	\
+		 HAL_REO_DESTINATION_RING_MSDU_COUNT_OFFSET)),	\
+		 HAL_REO_DESTINATION_RING_MSDU_COUNT_MASK,	\
+		 HAL_REO_DESTINATION_RING_MSDU_COUNT_LSB))
+
 #define HAL_BUFFER_ADDR_INFO_BUFFER_ADDR_31_0_OFFSET	0x0
 #define HAL_BUFFER_ADDR_INFO_BUFFER_ADDR_31_0_LSB	0
 #define HAL_BUFFER_ADDR_INFO_BUFFER_ADDR_31_0_MASK	0xffffffff
@@ -1323,6 +1333,20 @@ static inline bool hal_rx_reo_is_oor_error(uint32_t error_code)
 			true : false;
 }
 
+/**
+ * hal_rx_reo_is_bar_oor_2k_jump() - Check if the error is 2k-jump or OOR error
+ * @error_code: error code obtained from ring descriptor.
+ *
+ * Return: true, if the error code is 2k-jump or OOR
+ *	false, for other error codes.
+ */
+static inline bool hal_rx_reo_is_bar_oor_2k_jump(uint32_t error_code)
+{
+	return ((error_code == HAL_REO_ERR_BAR_FRAME_2K_JUMP) ||
+		(error_code == HAL_REO_ERR_BAR_FRAME_OOR)) ?
+		true : false;
+}
+
 /**
  * hal_dump_wbm_rel_desc() - dump wbm release descriptor
  * @hal_desc: hardware descriptor pointer
@@ -1690,6 +1714,27 @@ uint32_t hal_rx_desc_is_first_msdu(hal_soc_handle_t hal_soc_hdl,
 	return hal_soc->ops->hal_rx_desc_is_first_msdu(hw_desc_addr);
 }
 
+/**
+ * hal_rx_tlv_populate_mpdu_desc_info() - Populate mpdu_desc_info fields from
+ *					the rx tlv fields.
+ * @hal_soc_hdl: HAL SoC handle
+ * @buf: rx tlv start address [To be validated by caller]
+ * @mpdu_desc_info_hdl: Buffer where the mpdu_desc_info is to be populated.
+ *
+ * Return: None
+ */
+static inline void
+hal_rx_tlv_populate_mpdu_desc_info(hal_soc_handle_t hal_soc_hdl,
+				   uint8_t *buf,
+				   void *mpdu_desc_info_hdl)
+{
+	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
+
+	if (hal_soc->ops->hal_rx_tlv_populate_mpdu_desc_info)
+		return hal_soc->ops->hal_rx_tlv_populate_mpdu_desc_info(buf,
+							mpdu_desc_info_hdl);
+}
+
 static inline uint32_t
 hal_rx_tlv_decap_format_get(hal_soc_handle_t hal_soc_hdl, void *hw_desc_addr)
 {
@@ -2704,6 +2749,24 @@ hal_rx_reo_buf_type_get(hal_soc_handle_t hal_soc_hdl, hal_ring_desc_t rx_desc)
 	return hal_soc->ops->hal_rx_reo_buf_type_get(rx_desc);
 }
 
+/**
+ * hal_rx_reo_prev_pn_get() - Get the previous pn from ring descriptor.
+ * @hal_soc_hdl: HAL SoC handle
+ * @ring_desc: REO ring descriptor
+ * @prev_pn: Buffer to populate the previos PN
+ *
+ * Return: None
+ */
+static inline void
+hal_rx_reo_prev_pn_get(hal_soc_handle_t hal_soc_hdl, hal_ring_desc_t ring_desc,
+		       uint64_t *prev_pn)
+{
+	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
+
+	if (hal_soc->ops->hal_rx_reo_prev_pn_get)
+		return hal_soc->ops->hal_rx_reo_prev_pn_get(ring_desc, prev_pn);
+}
+
 /**
  * hal_rx_mpdu_info_ampdu_flag_get(): get ampdu flag bit
  * from rx mpdu info

+ 67 - 0
hal/wifi3.0/wcn7850/hal_7850.c

@@ -32,6 +32,9 @@
 #include "rx_flow_search_entry.h"
 #include "hal_rx_flow_info.h"
 #include "hal_be_api.h"
+#include "reo_destination_ring_with_pn.h"
+
+#include <hal_be_rx.h>
 
 #define UNIFIED_RXPCU_PPDU_END_INFO_8_RX_PPDU_DURATION_OFFSET \
 	RXPCU_PPDU_END_INFO_RX_PPDU_DURATION_OFFSET
@@ -713,6 +716,33 @@ static void hal_rx_dump_pkt_tlvs_7850(hal_soc_handle_t hal_soc_hdl,
 	hal_rx_dump_pkt_hdr_tlv_7850(pkt_tlvs, dbg_level);
 }
 
+/**
+ * hal_rx_tlv_populate_mpdu_desc_info_7850() - Populate the local mpdu_desc_info
+ *			elements from the rx tlvs
+ * @buf: start address of rx tlvs [Validated by caller]
+ * @mpdu_desc_info_hdl: Buffer to populate the mpdu_dsc_info
+ *			[To be validated by caller]
+ *
+ * Return: None
+ */
+static void
+hal_rx_tlv_populate_mpdu_desc_info_7850(uint8_t *buf,
+					void *mpdu_desc_info_hdl)
+{
+	struct hal_rx_mpdu_desc_info *mpdu_desc_info =
+		(struct hal_rx_mpdu_desc_info *)mpdu_desc_info_hdl;
+	struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf;
+	struct rx_mpdu_start *mpdu_start =
+					&pkt_tlvs->mpdu_start_tlv.rx_mpdu_start;
+	struct rx_mpdu_info *mpdu_info = &mpdu_start->rx_mpdu_info_details;
+
+	mpdu_desc_info->mpdu_seq = mpdu_info->mpdu_sequence_number;
+	mpdu_desc_info->mpdu_flags = hal_rx_get_mpdu_flags((uint32_t *)
+							    mpdu_info);
+	mpdu_desc_info->peer_meta_data = mpdu_info->peer_meta_data;
+	mpdu_desc_info->bar_frame = mpdu_info->bar_frame;
+}
+
 /**
  * hal_reo_status_get_header_7850 - Process reo desc info
  * @d - Pointer to reo descriptior
@@ -999,6 +1029,20 @@ hal_reo_set_err_dst_remap_7850(void *hal_soc)
 			 REO_REG_REG_BASE)));
 }
 
+/**
+ * hal_reo_enable_pn_in_dest_7850() - Set the REO register to enable previous PN
+ *				for OOR and 2K-jump frames
+ * @hal_soc: HAL SoC handle
+ *
+ * Return: 1, since the register is set.
+ */
+static uint8_t hal_reo_enable_pn_in_dest_7850(void *hal_soc)
+{
+	HAL_REG_WRITE(hal_soc, HWIO_REO_R0_PN_IN_DEST_ADDR(REO_REG_REG_BASE),
+		      1);
+	return 1;
+}
+
 /**
  * hal_rx_flow_setup_fse_7850() - Setup a flow search entry in HW FST
  * @fst: Pointer to the Rx Flow Search Table
@@ -1223,6 +1267,24 @@ static uint8_t hal_tx_get_num_tcl_banks_7850(void)
 	return HAL_NUM_TCL_BANKS_7850;
 }
 
+/**
+ * hal_rx_reo_prev_pn_get_7850() - Get the previous PN from the REO ring desc.
+ * @ring_desc: REO ring descriptor [To be validated by caller ]
+ * @prev_pn: Buffer where the previous PN is to be populated.
+ *		[To be validated by caller]
+ *
+ * Return: None
+ */
+static void hal_rx_reo_prev_pn_get_7850(void *ring_desc,
+					uint64_t *prev_pn)
+{
+	struct reo_destination_ring_with_pn *reo_desc =
+		(struct reo_destination_ring_with_pn *)ring_desc;
+
+	*prev_pn = reo_desc->prev_pn_23_0;
+	*prev_pn |= ((uint64_t)reo_desc->prev_pn_55_24 << 24);
+}
+
 static void hal_hw_txrx_ops_attach_wcn7850(struct hal_soc *hal_soc)
 {
 	/* init and setup */
@@ -1233,6 +1295,8 @@ static void hal_hw_txrx_ops_attach_wcn7850(struct hal_soc *hal_soc)
 	hal_soc->ops->hal_get_window_address = hal_get_window_address_7850;
 	hal_soc->ops->hal_reo_set_err_dst_remap =
 						hal_reo_set_err_dst_remap_7850;
+	hal_soc->ops->hal_reo_enable_pn_in_dest =
+						hal_reo_enable_pn_in_dest_7850;
 
 	/* tx */
 	hal_soc->ops->hal_tx_set_dscp_tid_map = hal_tx_set_dscp_tid_map_7850;
@@ -1383,6 +1447,7 @@ static void hal_hw_txrx_ops_attach_wcn7850(struct hal_soc *hal_soc)
 	hal_soc->ops->hal_rx_get_fisa_timeout = hal_rx_get_fisa_timeout_be;
 	hal_soc->ops->hal_rx_mpdu_start_tlv_tag_valid =
 		hal_rx_mpdu_start_tlv_tag_valid_be;
+	hal_soc->ops->hal_rx_reo_prev_pn_get = hal_rx_reo_prev_pn_get_7850;
 
 	/* rx - TLV struct offsets */
 	hal_soc->ops->hal_rx_msdu_end_offset_get =
@@ -1439,6 +1504,8 @@ static void hal_hw_txrx_ops_attach_wcn7850(struct hal_soc *hal_soc)
 					hal_rx_mpdu_info_ampdu_flag_get_be;
 	hal_soc->ops->hal_rx_tlv_msdu_len_set =
 					hal_rx_msdu_start_msdu_len_set_be;
+	hal_soc->ops->hal_rx_tlv_populate_mpdu_desc_info =
+				hal_rx_tlv_populate_mpdu_desc_info_7850;
 };
 
 struct hal_hw_srng_config hw_srng_table_7850[] = {