Parcourir la source

qcacmn: Add sg formation check

Add check for sg formation.
Only enable chfrag_cont and msdu_continuation if reo
error code is HAL_RX_WBM_ERR_SRC_REO or rxdma_err_code
is HAL_RXDMA_ERR_UNENCRYPTED.

Also chain all nbuf in case of sg in separate buffer
and finally loop through that. This is added because
sometime we dont get desc in sync with hw.
To avoid such mismatch, this buffer is added.
We will process nbuf only when all msdus has been
received.

Change-Id: I3b154a68955db61f3acaa0cb8d130c8918a3d450
CRs-Fixed: 2672126
Ankit Kumar il y a 5 ans
Parent
commit
8156bbf7fd
4 fichiers modifiés avec 109 ajouts et 13 suppressions
  1. 9 0
      dp/wifi3.0/dp_main.c
  2. 44 1
      dp/wifi3.0/dp_rx.h
  3. 46 12
      dp/wifi3.0/dp_rx_err.c
  4. 10 0
      dp/wifi3.0/dp_types.h

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

@@ -4109,6 +4109,9 @@ static void dp_soc_deinit(void *txrx_soc)
 
 	htt_soc_detach(htt_soc);
 
+	/* Free wbm sg list and reset flags in down path */
+	dp_rx_wbm_sg_list_deinit(soc);
+
 	wlan_minidump_remove(soc);
 }
 
@@ -10556,6 +10559,9 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc,
 	soc->osdev = qdf_osdev;
 	soc->num_hw_dscp_tid_map = HAL_MAX_HW_DSCP_TID_MAPS;
 
+	/* Reset wbm sg list and flags */
+	dp_rx_wbm_sg_list_reset(soc);
+
 	wlan_set_srng_cfg(&soc->wlan_srng_cfg);
 	soc->wlan_cfg_ctx = wlan_cfg_soc_attach(soc->ctrl_psoc);
 	if (!soc->wlan_cfg_ctx) {
@@ -10640,6 +10646,9 @@ void *dp_soc_init(struct dp_soc *soc, HTC_HANDLE htc_handle,
 
 	dp_soc_cfg_init(soc);
 
+	/* Reset/Initialize wbm sg list and flags */
+	dp_rx_wbm_sg_list_reset(soc);
+
 	/* Note: Any SRNG ring initialization should happen only after
 	 * Interrupt mode is set and followed by filling up the
 	 * interrupt mask. IT SHOULD ALWAYS BE IN THIS ORDER.

+ 44 - 1
dp/wifi3.0/dp_rx.h

@@ -690,6 +690,19 @@ void dp_2k_jump_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr,
 		qdf_nbuf_set_next((tail), NULL);                      \
 	} while (0)
 
+#define DP_RX_MERGE_TWO_LIST(phead, ptail, chead, ctail) \
+	do {                                                          \
+		if (!(phead)) {                                       \
+			(phead) = (chead);                            \
+		} else {                                              \
+			qdf_nbuf_set_next((ptail), (chead));          \
+			QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(phead) += \
+			QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(chead);   \
+		}                                                     \
+		(ptail) = (ctail);                                    \
+		qdf_nbuf_set_next((ptail), NULL);                     \
+	} while (0)
+
 /*for qcn9000 emulation the pcie is complete phy and no address restrictions*/
 #if !defined(BUILD_X86) || defined(QCA_WIFI_QCN9000)
 static inline int check_x86_paddr(struct dp_soc *dp_soc, qdf_nbuf_t *rx_netbuf,
@@ -1238,7 +1251,37 @@ dp_rx_srng_access_end(struct dp_intr *int_ctx, struct dp_soc *soc,
 {
 	dp_srng_access_end(int_ctx, soc, hal_ring_hdl);
 }
-
 #endif
 
+/*
+ * dp_rx_wbm_sg_list_reset() - Initialize sg list
+ *
+ * This api should be called at soc init and afterevery sg processing.
+ *@soc: DP SOC handle
+ */
+static inline void dp_rx_wbm_sg_list_reset(struct dp_soc *soc)
+{
+	if (soc) {
+		soc->wbm_sg_param.wbm_is_first_msdu_in_sg = false;
+		soc->wbm_sg_param.wbm_sg_nbuf_head = NULL;
+		soc->wbm_sg_param.wbm_sg_nbuf_tail = NULL;
+		soc->wbm_sg_param.wbm_sg_desc_msdu_len = 0;
+	}
+}
+
+/*
+ * dp_rx_wbm_sg_list_deinit() - De-initialize sg list
+ *
+ * This api should be called in down path, to avoid any leak.
+ *@soc: DP SOC handle
+ */
+static inline void dp_rx_wbm_sg_list_deinit(struct dp_soc *soc)
+{
+	if (soc) {
+		if (soc->wbm_sg_param.wbm_sg_nbuf_head)
+			qdf_nbuf_list_free(soc->wbm_sg_param.wbm_sg_nbuf_head);
+
+		dp_rx_wbm_sg_list_reset(soc);
+	}
+}
 #endif /* _DP_RX_H */

+ 46 - 12
dp/wifi3.0/dp_rx_err.c

@@ -1617,6 +1617,22 @@ static inline bool dp_handle_rxdma_decrypt_err(void)
 }
 #endif
 
+static inline bool
+dp_rx_is_sg_formation_required(struct hal_wbm_err_desc_info *info)
+{
+	/*
+	 * Currently Null Queue and Unencrypted error handlers has support for
+	 * SG. Other error handler do not deal with SG buffer.
+	 */
+	if (((info->wbm_err_src == HAL_RX_WBM_ERR_SRC_REO) &&
+	     (info->reo_err_code == HAL_REO_ERR_QUEUE_DESC_ADDR_0)) ||
+	    ((info->wbm_err_src == HAL_RX_WBM_ERR_SRC_RXDMA) &&
+	     (info->rxdma_err_code == HAL_RXDMA_ERR_UNENCRYPTED)))
+		return true;
+
+	return false;
+}
+
 uint32_t
 dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 		      hal_ring_handle_t hal_ring_hdl, uint32_t quota)
@@ -1642,8 +1658,7 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 	uint8_t pool_id;
 	uint8_t tid = 0;
 	uint8_t msdu_continuation = 0;
-	bool first_msdu_in_sg = false;
-	uint32_t msdu_len = 0;
+	bool process_sg_buf = false;
 
 	/* Debug -- Remove later */
 	qdf_assert(soc && hal_ring_hdl);
@@ -1742,28 +1757,34 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 						   ring_desc, rx_desc);
 		}
 
-		if (qdf_unlikely(soc->wbm_release_desc_rx_sg_support)) {
+		hal_rx_wbm_err_info_get(ring_desc, &wbm_err_info, hal_soc);
+
+		if (qdf_unlikely(soc->wbm_release_desc_rx_sg_support &&
+				 dp_rx_is_sg_formation_required(&wbm_err_info))) {
 			/* SG is detected from continuation bit */
 			msdu_continuation = hal_rx_wbm_err_msdu_continuation_get(hal_soc,
 					ring_desc);
-			if (msdu_continuation && !first_msdu_in_sg) {
+			if (msdu_continuation &&
+			    !(soc->wbm_sg_param.wbm_is_first_msdu_in_sg)) {
 				/* Update length from first buffer in SG */
-				msdu_len = hal_rx_msdu_start_msdu_len_get(
+				soc->wbm_sg_param.wbm_sg_desc_msdu_len =
+					hal_rx_msdu_start_msdu_len_get(
 						qdf_nbuf_data(rx_desc->nbuf));
-				first_msdu_in_sg = true;
-				QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = msdu_len;
+				soc->wbm_sg_param.wbm_is_first_msdu_in_sg = true;
 			}
 
 			if (msdu_continuation) {
 				/* MSDU continued packets */
 				qdf_nbuf_set_rx_chfrag_cont(rx_desc->nbuf, 1);
-				QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = msdu_len;
+				QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) =
+					soc->wbm_sg_param.wbm_sg_desc_msdu_len;
 			} else {
 				/* This is the terminal packet in SG */
 				qdf_nbuf_set_rx_chfrag_start(rx_desc->nbuf, 1);
 				qdf_nbuf_set_rx_chfrag_end(rx_desc->nbuf, 1);
-				QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = msdu_len;
-				first_msdu_in_sg = false;
+				QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) =
+					soc->wbm_sg_param.wbm_sg_desc_msdu_len;
+				process_sg_buf = true;
 			}
 		}
 
@@ -1774,14 +1795,27 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 		 * save the wbm desc info in nbuf TLV. We will need this
 		 * info when we do the actual nbuf processing
 		 */
-		hal_rx_wbm_err_info_get(ring_desc, &wbm_err_info, hal_soc);
 		wbm_err_info.pool_id = rx_desc->pool_id;
 		hal_rx_wbm_err_info_set_in_tlv(qdf_nbuf_data(nbuf),
 								&wbm_err_info);
 
 		rx_bufs_reaped[rx_desc->pool_id]++;
 
-		DP_RX_LIST_APPEND(nbuf_head, nbuf_tail, rx_desc->nbuf);
+		if (qdf_nbuf_is_rx_chfrag_cont(nbuf) || process_sg_buf) {
+			DP_RX_LIST_APPEND(soc->wbm_sg_param.wbm_sg_nbuf_head,
+					  soc->wbm_sg_param.wbm_sg_nbuf_tail,
+					  nbuf);
+			if (process_sg_buf) {
+				DP_RX_MERGE_TWO_LIST(nbuf_head, nbuf_tail,
+						     soc->wbm_sg_param.wbm_sg_nbuf_head,
+						     soc->wbm_sg_param.wbm_sg_nbuf_tail);
+				dp_rx_wbm_sg_list_reset(soc);
+				process_sg_buf = false;
+			}
+		} else {
+			DP_RX_LIST_APPEND(nbuf_head, nbuf_tail, nbuf);
+		}
+
 		dp_rx_add_to_free_desc_list(&head[rx_desc->pool_id],
 						&tail[rx_desc->pool_id],
 						rx_desc);

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

@@ -1326,6 +1326,16 @@ struct dp_soc {
 	/* SG supported for msdu continued packets from wbm release ring */
 	bool wbm_release_desc_rx_sg_support;
 	bool peer_map_attach_success;
+
+	struct {
+		/* 1st msdu in sg for msdu continued packets in wbm rel ring */
+		bool wbm_is_first_msdu_in_sg;
+		/* Wbm sg list head */
+		qdf_nbuf_t wbm_sg_nbuf_head;
+		/* Wbm sg list tail */
+		qdf_nbuf_t wbm_sg_nbuf_tail;
+		uint32_t wbm_sg_desc_msdu_len;
+	} wbm_sg_param;
 };
 
 #ifdef IPA_OFFLOAD