Forráskód Böngészése

qcacmn: Handle stale entry in tx completion ring

Currently SW writes a magic number in the tx completion
ring descriptor after reaping from the ring. This magic
number is used to determine, if the HP of the srng has been
updated without the contents of the ring descriptor has been
written.

There were cases of such stale entries observed and as a SW
workaround, add a logic to wait for a specific timeout for
the contents of the ring descriptor to be updated before
moving on to process subsequent ring entries.

Change-Id: I17c0dc0ac55ca81dee3c0825ce934d60ccb1a720
CRs-Fixed: 3648443
Rakesh Pillai 1 éve
szülő
commit
ab914e6f3e

+ 52 - 33
dp/wifi3.0/be/dp_be_tx.c

@@ -101,52 +101,63 @@ extern uint8_t sec_type_map[MAX_CDP_SEC_TYPE];
  * ring Desc is stale or not. if HW CC is not done, then compare PA between
  * ring Desc and current TX desc.
  *
- * Return: None.
+ * Return: QDF_STATUS_SUCCESS for success,
+ *	   QDF_STATUS_E_PENDING for stale entry,
+ *	   QDF_STATUS_E_INVAL for invalid entry.
  */
 static inline
-void dp_tx_comp_desc_check_and_invalidate(void *tx_comp_hal_desc,
-					  struct dp_tx_desc_s **r_tx_desc,
-					  uint64_t tx_desc_va,
-					  bool hw_cc_done)
+QDF_STATUS dp_tx_comp_desc_check_and_invalidate(void *tx_comp_hal_desc,
+						struct dp_tx_desc_s **r_tx_desc,
+						uint64_t tx_desc_va,
+						bool hw_cc_done)
 {
 	qdf_dma_addr_t desc_dma_addr;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	if (qdf_likely(hw_cc_done)) {
 		/* Check upper 32 bits */
 		if (DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE ==
-		    (tx_desc_va >> 32))
+		    (tx_desc_va >> 32)) {
 			*r_tx_desc = NULL;
-
-		/* Invalidate the ring desc for 32 ~ 63 bits of VA */
-		hal_tx_comp_set_desc_va_63_32(
+			status = QDF_STATUS_E_PENDING;
+		} else
+			/* Invalidate the ring desc for 32 ~ 63 bits of VA */
+			hal_tx_comp_set_desc_va_63_32(
 				tx_comp_hal_desc,
 				DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE);
 	} else {
 		/* Compare PA between ring desc and current TX desc stored */
 		desc_dma_addr = hal_tx_comp_get_paddr(tx_comp_hal_desc);
 
-		if (desc_dma_addr != (*r_tx_desc)->dma_addr)
+		if (desc_dma_addr != (*r_tx_desc)->dma_addr) {
 			*r_tx_desc = NULL;
+			status = QDF_STATUS_E_INVAL;
+		}
 	}
+
+	return status;
 }
 #else
 static inline
-void dp_tx_comp_desc_check_and_invalidate(void *tx_comp_hal_desc,
-					  struct dp_tx_desc_s **r_tx_desc,
-					  uint64_t tx_desc_va,
-					  bool hw_cc_done)
+QDF_STATUS dp_tx_comp_desc_check_and_invalidate(void *tx_comp_hal_desc,
+						struct dp_tx_desc_s **r_tx_desc,
+						uint64_t tx_desc_va,
+						bool hw_cc_done)
 {
+	return QDF_STATUS_SUCCESS;
 }
 #endif
 
 #ifdef DP_FEATURE_HW_COOKIE_CONVERSION
 #ifdef DP_HW_COOKIE_CONVERT_EXCEPTION
-void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc)
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc)
 {
 	uint32_t tx_desc_id;
 	uint64_t tx_desc_va = 0;
+	QDF_STATUS status;
 	bool hw_cc_done =
 		hal_tx_comp_get_cookie_convert_done(tx_comp_hal_desc);
 
@@ -162,56 +173,64 @@ void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
 		(struct dp_tx_desc_s *)dp_cc_desc_find(soc, tx_desc_id);
 	}
 
-	dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc,
-					     r_tx_desc, tx_desc_va,
-					     hw_cc_done);
+	status = dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc,
+						      r_tx_desc, tx_desc_va,
+						      hw_cc_done);
 
 	if (*r_tx_desc)
 		(*r_tx_desc)->peer_id =
 				dp_tx_comp_get_peer_id_be(soc,
 							  tx_comp_hal_desc);
+
+	return status;
 }
 #else
-void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc)
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc)
 {
 	uint64_t tx_desc_va;
+	QDF_STATUS status;
 
 	tx_desc_va = hal_tx_comp_get_desc_va(tx_comp_hal_desc);
 	*r_tx_desc = (struct dp_tx_desc_s *)(uintptr_t)tx_desc_va;
 
-	dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc,
-					     r_tx_desc,
-					     tx_desc_va,
-					     true);
+	status = dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc,
+						      r_tx_desc, tx_desc_va,
+						      true);
 	if (*r_tx_desc)
 		(*r_tx_desc)->peer_id =
 				dp_tx_comp_get_peer_id_be(soc,
 							  tx_comp_hal_desc);
+
+	return status;
 }
 #endif /* DP_HW_COOKIE_CONVERT_EXCEPTION */
 #else
 
-void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc)
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc)
 {
 	uint32_t tx_desc_id;
+	QDF_STATUS status;
 
 	/* SW do cookie conversion to VA */
 	tx_desc_id = hal_tx_comp_get_desc_id(tx_comp_hal_desc);
 	*r_tx_desc =
 	(struct dp_tx_desc_s *)dp_cc_desc_find(soc, tx_desc_id);
 
-	dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc,
-					     r_tx_desc, 0,
-					     false);
+	status = dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc,
+						      r_tx_desc, 0, false);
 
 	if (*r_tx_desc)
 		(*r_tx_desc)->peer_id =
 				dp_tx_comp_get_peer_id_be(soc,
 							  tx_comp_hal_desc);
+
+	return status;
 }
 #endif /* DP_FEATURE_HW_COOKIE_CONVERSION */
 

+ 5 - 4
dp/wifi3.0/be/dp_be_tx.h

@@ -138,11 +138,12 @@ static inline qdf_nbuf_t dp_tx_fast_send_be(struct cdp_soc_t *soc, uint8_t vdev_
  * @tx_comp_hal_desc: HAL TX Comp Descriptor
  * @r_tx_desc: SW Tx Descriptor retrieved from HAL desc.
  *
- * Return: None
+ * Return: QDF_STATUS
  */
-void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc);
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc);
 
 /**
  * dp_tx_process_htt_completion_be() - Tx HTT Completion Indication Handler

+ 77 - 3
dp/wifi3.0/dp_tx.c

@@ -6600,6 +6600,70 @@ void dp_tx_desc_check_corruption(struct dp_tx_desc_s *tx_desc)
 #endif
 
 #ifndef WLAN_SOFTUMAC_SUPPORT
+#ifdef DP_TX_COMP_RING_DESC_SANITY_CHECK
+
+/* Increasing this value, runs the risk of srng backpressure */
+#define DP_STALE_TX_COMP_WAIT_TIMEOUT_US 1000
+
+static inline void
+dp_tx_comp_reset_stale_entry_detection(struct dp_soc *soc, uint32_t ring_num)
+{
+	soc->stale_entry[ring_num].detected = 0;
+}
+
+/**
+ * dp_tx_comp_stale_entry_handle() - Detect stale entry condition in tx
+ *				     completion srng.
+ * @soc: DP SoC handle
+ * @ring_num: tx completion ring number
+ * @status: QDF_STATUS from tx_comp_get_params_from_hal_desc arch ops
+ *
+ * Return: QDF_STATUS_SUCCESS if stale entry is detected and handled
+ *	   QDF_STATUS error code in other cases.
+ */
+static inline QDF_STATUS
+dp_tx_comp_stale_entry_handle(struct dp_soc *soc, uint32_t ring_num,
+			      QDF_STATUS status)
+{
+	uint64_t curr_timestamp = qdf_get_log_timestamp_usecs();
+	uint64_t delta_us;
+
+	if (status != QDF_STATUS_E_PENDING) {
+		dp_tx_comp_reset_stale_entry_detection(soc, ring_num);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (soc->stale_entry[ring_num].detected) {
+		/* stale entry process continuation */
+		delta_us = curr_timestamp -
+				soc->stale_entry[ring_num].start_time;
+		if (delta_us > DP_STALE_TX_COMP_WAIT_TIMEOUT_US) {
+			dp_err("Stale tx comp desc, waited %d us", delta_us);
+			return QDF_STATUS_E_FAILURE;
+		}
+	} else {
+		/* This is the start of stale entry detection */
+		soc->stale_entry[ring_num].detected = 1;
+		soc->stale_entry[ring_num].start_time = curr_timestamp;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+
+static inline void
+dp_tx_comp_reset_stale_entry_detection(struct dp_soc *soc, uint32_t ring_num)
+{
+}
+
+static inline QDF_STATUS
+dp_tx_comp_stale_entry_handle(struct dp_soc *soc, uint32_t ring_num,
+			      QDF_STATUS status)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 uint32_t dp_tx_comp_handler(struct dp_intr *int_ctx, struct dp_soc *soc,
 			    hal_ring_handle_t hal_ring_hdl, uint8_t ring_id,
 			    uint32_t quota)
@@ -6623,6 +6687,7 @@ uint32_t dp_tx_comp_handler(struct dp_intr *int_ctx, struct dp_soc *soc,
 	int max_reap_limit, ring_near_full;
 	uint32_t num_entries;
 	qdf_nbuf_queue_head_t h;
+	QDF_STATUS status;
 
 	DP_HIST_INIT();
 
@@ -6715,16 +6780,25 @@ more_data:
 			continue;
 		}
 
-		soc->arch_ops.tx_comp_get_params_from_hal_desc(soc,
-							       tx_comp_hal_desc,
-							       &tx_desc);
+		status = soc->arch_ops.tx_comp_get_params_from_hal_desc(
+							soc, tx_comp_hal_desc,
+							&tx_desc);
 		if (qdf_unlikely(!tx_desc)) {
+			if (QDF_IS_STATUS_SUCCESS(
+				dp_tx_comp_stale_entry_handle(soc, ring_id,
+							      status))) {
+				hal_srng_dst_dec_tp(hal_soc, hal_ring_hdl);
+				break;
+			}
+
 			dp_err("unable to retrieve tx_desc!");
 			hal_dump_comp_desc(tx_comp_hal_desc);
 			DP_STATS_INC(soc, tx.invalid_tx_comp_desc, 1);
 			QDF_BUG(0);
 			continue;
 		}
+
+		dp_tx_comp_reset_stale_entry_detection(soc, ring_id);
 		tx_desc->buffer_src = buffer_src;
 
 		/*

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

@@ -2328,9 +2328,9 @@ struct dp_arch_ops {
 				    struct cdp_tx_exception_metadata *metadata,
 				    struct dp_tx_msdu_info_s *msdu_info);
 
-	void (*tx_comp_get_params_from_hal_desc)(struct dp_soc *soc,
-						 void *tx_comp_hal_desc,
-						 struct dp_tx_desc_s **desc);
+	QDF_STATUS (*tx_comp_get_params_from_hal_desc)(
+				struct dp_soc *soc, void *tx_comp_hal_desc,
+				struct dp_tx_desc_s **desc);
 
 	qdf_nbuf_t (*dp_tx_mlo_mcast_send)(struct dp_soc *soc,
 					   struct dp_vdev *vdev,
@@ -3205,6 +3205,13 @@ struct dp_soc {
 	/* callback function for tx latency stats */
 	cdp_tx_latency_cb tx_latency_cb;
 #endif
+
+#ifdef DP_TX_COMP_RING_DESC_SANITY_CHECK
+	struct {
+		uint32_t detected;
+		uint64_t start_time;
+	} stale_entry[MAX_TCL_DATA_RINGS];
+#endif
 };
 
 #ifdef IPA_OFFLOAD

+ 6 - 3
dp/wifi3.0/li/dp_li_tx.c

@@ -33,9 +33,10 @@
 
 extern uint8_t sec_type_map[MAX_CDP_SEC_TYPE];
 
-void dp_tx_comp_get_params_from_hal_desc_li(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc)
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_li(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc)
 {
 	uint8_t pool_id;
 	uint32_t tx_desc_id;
@@ -60,6 +61,8 @@ void dp_tx_comp_get_params_from_hal_desc_li(struct dp_soc *soc,
 	}
 
 	(*r_tx_desc)->peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc);
+
+	return QDF_STATUS_SUCCESS;
 }
 
 static inline

+ 5 - 4
dp/wifi3.0/li/dp_li_tx.h

@@ -47,11 +47,12 @@ dp_tx_hw_enqueue_li(struct dp_soc *soc, struct dp_vdev *vdev,
  * @tx_comp_hal_desc: HAL TX Comp Descriptor
  * @r_tx_desc: SW Tx Descriptor retrieved from HAL desc.
  *
- * Return: None
+ * Return: QDF_STATUS
  */
-void dp_tx_comp_get_params_from_hal_desc_li(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc);
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_li(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc);
 
 /**
  * dp_tx_process_htt_completion_li() - Tx HTT Completion Indication Handler

+ 5 - 3
dp/wifi3.0/rh/dp_rh_tx.c

@@ -75,10 +75,12 @@ dp_tx_adjust_tso_download_len_rh(qdf_nbuf_t nbuf,
 }
 #endif /* FEATURE_TSO */
 
-void dp_tx_comp_get_params_from_hal_desc_rh(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc)
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_rh(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc)
 {
+	return QDF_STATUS_SUCCESS;
 }
 
 /**

+ 5 - 4
dp/wifi3.0/rh/dp_rh_tx.h

@@ -76,11 +76,12 @@ dp_tx_hw_enqueue_rh(struct dp_soc *soc, struct dp_vdev *vdev,
  * @tx_comp_hal_desc: HAL TX Comp Descriptor
  * @r_tx_desc: SW Tx Descriptor retrieved from HAL desc.
  *
- * Return: None
+ * Return: QDF_STATUS return codes
  */
-void dp_tx_comp_get_params_from_hal_desc_rh(struct dp_soc *soc,
-					    void *tx_comp_hal_desc,
-					    struct dp_tx_desc_s **r_tx_desc);
+QDF_STATUS
+dp_tx_comp_get_params_from_hal_desc_rh(struct dp_soc *soc,
+				       void *tx_comp_hal_desc,
+				       struct dp_tx_desc_s **r_tx_desc);
 
 /**
  * dp_tx_process_htt_completion_rh() - Tx HTT Completion Indication Handler