فهرست منبع

qcacmn: Add TX completion ring desc sanity check

Suspect HW update WBM2SW ring HP, but the ring entry contents are
not updated accordingly which then host will fetch one stale ring entry,
this makes other TX packet are freed unexpectedlly.

Add change to detect this situation earlier, if HW cookie conversion is
done, then invalidate 2nd dword for upper 32bits of VA, so next time when
reap this ring entry contents to know if this desc is updated by
HW or not. if HW cookie conversion is not done, then compare the PA in
buff_addr_info with PA in current TX desc to check.

Change-Id: I351eb4f860216fc618ff28736d4832fcec45dcc5
CRs-Fixed: 3345935
Jinwei Chen 2 سال پیش
والد
کامیت
1bf08f3566
7فایلهای تغییر یافته به همراه140 افزوده شده و 36 حذف شده
  1. 2 0
      dp/inc/cdp_txrx_stats_struct.h
  2. 81 30
      dp/wifi3.0/be/dp_be_tx.c
  3. 27 0
      dp/wifi3.0/be/dp_be_tx.h
  4. 6 0
      dp/wifi3.0/dp_stats.c
  5. 3 1
      dp/wifi3.0/dp_tx.c
  6. 5 3
      dp/wifi3.0/dp_types.h
  7. 16 2
      hal/wifi3.0/be/hal_be_tx.h

+ 2 - 0
dp/inc/cdp_txrx_stats_struct.h

@@ -2634,6 +2634,7 @@ struct cdp_per_cpu_packets {
  * @tx.desc_in_use: Descriptors in use at soc
  * @tx.dropped_fw_removed: HW_release_reason == FW removed
  * @tx.invalid_release_source: tx completion release_src != HW or FW
+ * @tx.invalid_tx_comp_desc: TX Desc from completion ring Desc is not valid
  * @tx.wifi_internal_error: tx completion wifi_internal_error
  * @tx.non_wifi_internal_err: tx completion non_wifi_internal_error
  * @tx.tx_comp_loop_pkt_limit_hit: TX Comp loop packet limit hit
@@ -2717,6 +2718,7 @@ struct cdp_soc_stats {
 		uint32_t desc_in_use;
 		uint32_t dropped_fw_removed;
 		uint32_t invalid_release_source;
+		uint32_t invalid_tx_comp_desc;
 		uint32_t wifi_internal_error[CDP_MAX_WIFI_INT_ERROR_REASONS];
 		uint32_t non_wifi_internal_err;
 		uint32_t tx_comp_loop_pkt_limit_hit;

+ 81 - 30
dp/wifi3.0/be/dp_be_tx.c

@@ -79,29 +79,60 @@ struct dp_mlo_mpass_buf {
 
 extern uint8_t sec_type_map[MAX_CDP_SEC_TYPE];
 
-#ifdef DP_USE_REDUCED_PEER_ID_FIELD_WIDTH
-static inline uint16_t dp_tx_comp_get_peer_id(struct dp_soc *soc,
-					      void *tx_comp_hal_desc)
+#ifdef DP_TX_COMP_RING_DESC_SANITY_CHECK
+/*
+ * Value to mark ring desc is invalidated by buffer_virt_addr_63_32 field
+ * of WBM2SW ring Desc.
+ */
+#define DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE 0x12121212
+
+/**
+ * dp_tx_comp_desc_check_and_invalidate() - sanity check for ring desc and
+ *					    invalidate it after each reaping
+ * @tx_comp_hal_desc: ring desc virtual address
+ * @r_tx_desc: pointer to current dp TX Desc pointer
+ * @tx_desc_va: the original 64 bits Desc VA got from ring Desc
+ * @hw_cc_done: HW cookie conversion done or not
+ *
+ * If HW CC is done, check the buffer_virt_addr_63_32 value to know if
+ * ring Desc is stale or not. if HW CC is not done, then compare PA between
+ * ring Desc and current TX desc.
+ *
+ * Return: None.
+ */
+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)
 {
-	uint16_t peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc);
-	struct dp_tx_comp_peer_id *tx_peer_id =
-			(struct dp_tx_comp_peer_id *)&peer_id;
+	qdf_dma_addr_t desc_dma_addr;
+
+	if (qdf_likely(hw_cc_done)) {
+		/* Check upper 32 bits */
+		if (DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE ==
+		    (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(
+				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);
 
-	return (tx_peer_id->peer_id |
-	        (tx_peer_id->ml_peer_valid << soc->peer_id_shift));
+		if (desc_dma_addr != (*r_tx_desc)->dma_addr)
+			*r_tx_desc = NULL;
+	}
 }
 #else
-/* Combine ml_peer_valid and peer_id field */
-#define DP_BE_TX_COMP_PEER_ID_MASK	0x00003fff
-#define DP_BE_TX_COMP_PEER_ID_SHIFT	0
-
-static inline uint16_t dp_tx_comp_get_peer_id(struct dp_soc *soc,
-					      void *tx_comp_hal_desc)
+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)
 {
-	uint16_t peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc);
-
-	return ((peer_id & DP_BE_TX_COMP_PEER_ID_MASK) >>
-		DP_BE_TX_COMP_PEER_ID_SHIFT);
 }
 #endif
 
@@ -112,12 +143,15 @@ void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
 					    struct dp_tx_desc_s **r_tx_desc)
 {
 	uint32_t tx_desc_id;
+	uint64_t tx_desc_va = 0;
+	bool hw_cc_done =
+		hal_tx_comp_get_cookie_convert_done(tx_comp_hal_desc);
 
-	if (qdf_likely(
-		hal_tx_comp_get_cookie_convert_done(tx_comp_hal_desc))) {
+	if (qdf_likely(hw_cc_done)) {
 		/* HW cookie conversion done */
-		*r_tx_desc = (struct dp_tx_desc_s *)
-				hal_tx_comp_get_desc_va(tx_comp_hal_desc);
+		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;
+
 	} else {
 		/* SW do cookie conversion to VA */
 		tx_desc_id = hal_tx_comp_get_desc_id(tx_comp_hal_desc);
@@ -125,21 +159,33 @@ 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);
+
 	if (*r_tx_desc)
-		(*r_tx_desc)->peer_id = dp_tx_comp_get_peer_id(soc,
-							       tx_comp_hal_desc);
+		(*r_tx_desc)->peer_id =
+				dp_tx_comp_get_peer_id_be(soc,
+							  tx_comp_hal_desc);
 }
 #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)
 {
-	*r_tx_desc = (struct dp_tx_desc_s *)
-			hal_tx_comp_get_desc_va(tx_comp_hal_desc);
+	uint64_t tx_desc_va;
 
+	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);
 	if (*r_tx_desc)
-		(*r_tx_desc)->peer_id = dp_tx_comp_get_peer_id(soc,
-							       tx_comp_hal_desc);
+		(*r_tx_desc)->peer_id =
+				dp_tx_comp_get_peer_id_be(soc,
+							  tx_comp_hal_desc);
 }
 #endif /* DP_HW_COOKIE_CONVERT_EXCEPTION */
 #else
@@ -155,9 +201,14 @@ void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc,
 	*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);
+
 	if (*r_tx_desc)
-		(*r_tx_desc)->peer_id = dp_tx_comp_get_peer_id(soc,
-							       tx_comp_hal_desc);
+		(*r_tx_desc)->peer_id =
+				dp_tx_comp_get_peer_id_be(soc,
+							  tx_comp_hal_desc);
 }
 #endif /* DP_FEATURE_HW_COOKIE_CONVERSION */
 

+ 27 - 0
dp/wifi3.0/be/dp_be_tx.h

@@ -49,6 +49,33 @@ struct __attribute__((__packed__)) dp_tx_comp_peer_id {
 #define DP_TX_FAST_DESC_SIZE	24
 #define DP_TX_L3_L4_CSUM_ENABLE	0x1f
 
+#ifdef DP_USE_REDUCED_PEER_ID_FIELD_WIDTH
+/**
+ * dp_tx_comp_get_peer_id_be() - Get peer ID from TX Comp Desc
+ * @soc: Handle to DP Soc structure
+ * @tx_comp_hal_desc: TX comp ring descriptor
+ *
+ * Return: Peer ID
+ */
+static inline uint16_t dp_tx_comp_get_peer_id_be(struct dp_soc *soc,
+						 void *tx_comp_hal_desc)
+{
+	uint16_t peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc);
+	struct dp_tx_comp_peer_id *tx_peer_id =
+			(struct dp_tx_comp_peer_id *)&peer_id;
+
+	return (tx_peer_id->peer_id |
+		(tx_peer_id->ml_peer_valid << soc->peer_id_shift));
+}
+#else
+static inline uint16_t dp_tx_comp_get_peer_id_be(struct dp_soc *soc,
+						 void *tx_comp_hal_desc)
+{
+	return hal_tx_comp_get_peer_id(tx_comp_hal_desc);
+
+}
+#endif
+
 /**
  * dp_tx_hw_enqueue_be() - Enqueue to TCL HW for transmit for BE target
  * @soc: DP Soc Handle

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

@@ -7165,6 +7165,8 @@ void dp_txrx_path_stats(struct dp_soc *soc)
 
 		DP_PRINT_STATS("Invalid release source: %u",
 			       soc->stats.tx.invalid_release_source);
+		DP_PRINT_STATS("Invalid TX desc from completion ring: %u",
+			       soc->stats.tx.invalid_tx_comp_desc);
 		DP_PRINT_STATS("Dropped in host:");
 		DP_PRINT_STATS("Total packets dropped: %u,",
 			       pdev->stats.tx_i.dropped.dropped_pkt.num);
@@ -7714,6 +7716,8 @@ dp_print_soc_tx_stats(struct dp_soc *soc)
 		       soc->stats.tx.tcl_ring_full[3]);
 	DP_PRINT_STATS("Tx invalid completion release = %u",
 		       soc->stats.tx.invalid_release_source);
+	DP_PRINT_STATS("TX invalid Desc from completion ring = %u",
+		       soc->stats.tx.invalid_tx_comp_desc);
 	DP_PRINT_STATS("Tx comp wbm internal error = %d : [%d %d %d %d]",
 		       soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_ALL],
 		       soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_BUFFER],
@@ -8860,6 +8864,8 @@ QDF_STATUS dp_txrx_get_soc_stats(struct cdp_soc_t *soc_hdl,
 	soc_stats->tx.dropped_fw_removed = soc->stats.tx.dropped_fw_removed;
 	soc_stats->tx.invalid_release_source =
 					soc->stats.tx.invalid_release_source;
+	soc_stats->tx.invalid_tx_comp_desc =
+					soc->stats.tx.invalid_tx_comp_desc;
 	for (inx = 0; inx < CDP_MAX_WIFI_INT_ERROR_REASONS; inx++)
 		soc_stats->tx.wifi_internal_error[inx] =
 					soc->stats.tx.wbm_internal_error[inx];

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

@@ -5825,8 +5825,10 @@ more_data:
 		soc->arch_ops.tx_comp_get_params_from_hal_desc(soc,
 							       tx_comp_hal_desc,
 							       &tx_desc);
-		if (!tx_desc) {
+		if (qdf_unlikely(!tx_desc)) {
 			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;
 		}

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

@@ -1097,6 +1097,8 @@ struct dp_soc_stats {
 		uint32_t dropped_fw_removed;
 		/* tx completion release_src != TQM or FW */
 		uint32_t invalid_release_source;
+		/* TX descriptor from completion ring Desc is not valid */
+		uint32_t invalid_tx_comp_desc;
 		/* tx completion wbm_internal_error */
 		uint32_t wbm_internal_error[MAX_WBM_INT_ERROR_REASONS];
 		/* tx completion non_wbm_internal_error */
@@ -1885,9 +1887,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);
+	void (*tx_comp_get_params_from_hal_desc)(struct dp_soc *soc,
+						 void *tx_comp_hal_desc,
+						 struct dp_tx_desc_s **desc);
 	void (*dp_tx_process_htt_completion)(struct dp_soc *soc,
 					     struct dp_tx_desc_s *tx_desc,
 					     uint8_t *status,

+ 16 - 2
hal/wifi3.0/be/hal_be_tx.h

@@ -570,6 +570,20 @@ static inline uint8_t hal_tx_comp_get_cookie_convert_done(void *hal_desc)
 }
 #endif
 
+/**
+ * hal_tx_comp_set_desc_va_63_32() - Set bit 32~63 value for 64 bit VA
+ * @hal_desc: completion ring descriptor pointer
+ * @val: value to be set
+ *
+ * Return: None
+ */
+static inline void hal_tx_comp_set_desc_va_63_32(void *hal_desc, uint32_t val)
+{
+	HAL_SET_FLD(hal_desc,
+		    WBM2SW_COMPLETION_RING_TX,
+		    BUFFER_VIRT_ADDR_63_32) = val;
+}
+
 /**
  * hal_tx_comp_get_desc_va() - Get Desc virtual address within completion Desc
  * @hal_desc: completion ring descriptor pointer
@@ -578,7 +592,7 @@ static inline uint8_t hal_tx_comp_get_cookie_convert_done(void *hal_desc)
  *
  * Return: TX desc virtual address
  */
-static inline uintptr_t hal_tx_comp_get_desc_va(void *hal_desc)
+static inline uint64_t hal_tx_comp_get_desc_va(void *hal_desc)
 {
 	uint64_t va_from_desc;
 
@@ -590,7 +604,7 @@ static inline uintptr_t hal_tx_comp_get_desc_va(void *hal_desc)
 					WBM2SW_COMPLETION_RING_TX,
 					BUFFER_VIRT_ADDR_63_32)) << 32);
 
-	return (uintptr_t)va_from_desc;
+	return va_from_desc;
 }
 
 /*---------------------------------------------------------------------------