Browse Source

qcacmn: Handle wbm_internal_error in tx completions

Handle wbm_internal_error in tx completions by releasing
associated descriptors and buffers.

Change-Id: I94d334c90c0514674323430fe53da72fb5424576
Pavankumar Nandeshwar 5 years ago
parent
commit
b86ddaf205
6 changed files with 181 additions and 4 deletions
  1. 150 0
      dp/wifi3.0/dp_rx_err.c
  2. 6 2
      dp/wifi3.0/dp_stats.c
  3. 10 1
      dp/wifi3.0/dp_tx.c
  4. 4 0
      dp/wifi3.0/dp_tx.h
  5. 8 1
      dp/wifi3.0/dp_types.h
  6. 3 0
      hal/wifi3.0/hal_tx.h

+ 150 - 0
dp/wifi3.0/dp_rx_err.c

@@ -1834,3 +1834,153 @@ dp_rxdma_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 
 	return work_done;
 }
+
+static inline uint32_t
+dp_wbm_int_err_mpdu_pop(struct dp_soc *soc, uint32_t mac_id,
+			hal_rxdma_desc_t rxdma_dst_ring_desc,
+			union dp_rx_desc_list_elem_t **head,
+			union dp_rx_desc_list_elem_t **tail)
+{
+	void *rx_msdu_link_desc;
+	qdf_nbuf_t msdu;
+	qdf_nbuf_t last;
+	struct hal_rx_msdu_list msdu_list;
+	uint16_t num_msdus;
+	struct hal_buf_info buf_info;
+	void *p_buf_addr_info;
+	void *p_last_buf_addr_info;
+	uint32_t rx_bufs_used = 0;
+	uint32_t msdu_cnt;
+	uint32_t i;
+
+	msdu = 0;
+
+	last = NULL;
+
+	hal_rx_reo_ent_buf_paddr_get(rxdma_dst_ring_desc, &buf_info,
+				     &p_last_buf_addr_info, &msdu_cnt);
+
+	do {
+		rx_msdu_link_desc =
+			dp_rx_cookie_2_link_desc_va(soc, &buf_info);
+
+		if (!rx_msdu_link_desc) {
+			DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_LINK_DESC], 1);
+			break;
+		}
+
+		hal_rx_msdu_list_get(soc->hal_soc, rx_msdu_link_desc,
+				     &msdu_list, &num_msdus);
+
+		if (msdu_list.sw_cookie[0] != HAL_RX_COOKIE_SPECIAL) {
+			for (i = 0; i < num_msdus; i++) {
+				struct dp_rx_desc *rx_desc =
+					dp_rx_cookie_2_va_rxdma_buf(
+							soc,
+							msdu_list.sw_cookie[i]);
+				qdf_assert_always(rx_desc);
+				msdu = rx_desc->nbuf;
+
+				qdf_nbuf_unmap_single(soc->osdev, msdu,
+						      QDF_DMA_FROM_DEVICE);
+
+				qdf_nbuf_free(msdu);
+				rx_bufs_used++;
+				dp_rx_add_to_free_desc_list(head,
+							    tail, rx_desc);
+			}
+		}
+
+		hal_rx_mon_next_link_desc_get(rx_msdu_link_desc, &buf_info,
+					      &p_buf_addr_info);
+
+		dp_rx_link_desc_return(soc, p_last_buf_addr_info,
+				       HAL_BM_ACTION_PUT_IN_IDLE_LIST);
+		p_last_buf_addr_info = p_buf_addr_info;
+
+	} while (buf_info.paddr);
+
+	return rx_bufs_used;
+}
+
+/*
+ *
+ * dp_handle_wbm_internal_error() - handles wbm_internal_error case
+ *
+ * @soc: core DP main context
+ * @hal_desc: hal descriptor
+ * @buf_type: indicates if the buffer is of type link disc or msdu
+ * Return: None
+ *
+ * wbm_internal_error is seen in following scenarios :
+ *
+ * 1.  Null pointers detected in WBM_RELEASE_RING descriptors
+ * 2.  Null pointers detected during delinking process
+ *
+ * Some null pointer cases:
+ *
+ * a. MSDU buffer pointer is NULL
+ * b. Next_MSDU_Link_Desc pointer is NULL, with no last msdu flag
+ * c. MSDU buffer pointer is NULL or Next_Link_Desc pointer is NULL
+ */
+void
+dp_handle_wbm_internal_error(struct dp_soc *soc, void *hal_desc,
+			     uint32_t buf_type)
+{
+	struct hal_buf_info buf_info = {0};
+	struct dp_pdev *dp_pdev;
+	struct dp_rx_desc *rx_desc = NULL;
+	uint32_t rx_buf_cookie;
+	uint32_t rx_bufs_reaped = 0;
+	union dp_rx_desc_list_elem_t *head = NULL;
+	union dp_rx_desc_list_elem_t *tail = NULL;
+	uint8_t pool_id;
+
+	hal_rx_reo_buf_paddr_get(hal_desc, &buf_info);
+
+	if (!buf_info.paddr) {
+		DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_BUFFER], 1);
+		return;
+	}
+
+	rx_buf_cookie = HAL_RX_REO_BUF_COOKIE_GET(hal_desc);
+	pool_id = DP_RX_DESC_COOKIE_POOL_ID_GET(rx_buf_cookie);
+
+	if (buf_type == HAL_WBM_RELEASE_RING_2_BUFFER_TYPE) {
+		DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_MSDU_BUFF], 1);
+		rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, rx_buf_cookie);
+
+		if (rx_desc && rx_desc->nbuf) {
+			qdf_nbuf_unmap_single(soc->osdev, rx_desc->nbuf,
+					      QDF_DMA_FROM_DEVICE);
+
+			rx_desc->unmapped = 1;
+
+			qdf_nbuf_free(rx_desc->nbuf);
+			dp_rx_add_to_free_desc_list(&head,
+						    &tail,
+						    rx_desc);
+
+			rx_bufs_reaped++;
+		}
+	} else if (buf_type == HAL_WBM_RELEASE_RING_2_DESC_TYPE) {
+		rx_bufs_reaped = dp_wbm_int_err_mpdu_pop(soc, pool_id,
+							 hal_desc,
+							 &head, &tail);
+	}
+
+	if (rx_bufs_reaped) {
+		struct rx_desc_pool *rx_desc_pool;
+		struct dp_srng *dp_rxdma_srng;
+
+		DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_BUFF_REAPED], 1);
+		dp_pdev = soc->pdev_list[pool_id];
+		dp_rxdma_srng = &dp_pdev->rx_refill_buf_ring;
+		rx_desc_pool = &soc->rx_desc_buf[pool_id];
+
+		dp_rx_buffers_replenish(soc, pool_id, dp_rxdma_srng,
+					rx_desc_pool,
+					rx_bufs_reaped,
+					&head, &tail);
+	}
+}

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

@@ -5597,8 +5597,12 @@ dp_print_soc_tx_stats(struct dp_soc *soc)
 		       soc->stats.tx.tcl_ring_full[2]);
 	DP_PRINT_STATS("Tx invalid completion release = %d",
 		       soc->stats.tx.invalid_release_source);
-	DP_PRINT_STATS("Tx comp wbm internal error = %d",
-		       soc->stats.tx.wbm_internal_error);
+	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],
+		       soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_LINK_DESC],
+		       soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_MSDU_BUFF],
+		       soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_BUFF_REAPED]);
 	DP_PRINT_STATS("Tx comp loop pkt limit hit = %d",
 		       soc->stats.tx.tx_comp_loop_pkt_limit_hit);
 	DP_PRINT_STATS("Tx comp HP out of sync2 = %d",

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

@@ -3472,7 +3472,16 @@ more_data:
 				QDF_TRACE(QDF_MODULE_ID_DP,
 					  QDF_TRACE_LEVEL_ERROR,
 					  "Tx comp wbm_internal_error!!!\n");
-				DP_STATS_INC(soc, tx.wbm_internal_error, 1);
+				DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_ALL], 1);
+
+				if (HAL_TX_COMP_RELEASE_SOURCE_REO ==
+								buffer_src)
+					dp_handle_wbm_internal_error(
+						soc,
+						tx_comp_hal_desc,
+						hal_tx_comp_get_buffer_type(
+							tx_comp_hal_desc));
+
 				continue;
 			} else {
 				qdf_assert_always(0);

+ 4 - 0
dp/wifi3.0/dp_tx.h

@@ -330,6 +330,10 @@ void  dp_iterate_update_peer_list(struct cdp_pdev *pdev_hdl);
 #define DP_TX_TID_OVERRIDE(_msdu_info, _nbuf)
 #endif
 
+void
+dp_handle_wbm_internal_error(struct dp_soc *soc, void *hal_desc,
+			     uint32_t buf_type);
+
 /* TODO TX_FEATURE_NOT_YET */
 static inline void dp_tx_comp_process_exception(struct dp_tx_desc_s *tx_desc)
 {

+ 8 - 1
dp/wifi3.0/dp_types.h

@@ -88,6 +88,13 @@
 #define DP_MAX_IRQ_PER_CONTEXT 12
 #define DEFAULT_HW_PEER_ID 0xffff
 
+#define WBM_INT_ERROR_ALL 0
+#define WBM_INT_ERROR_REO_NULL_BUFFER 1
+#define WBM_INT_ERROR_REO_NULL_LINK_DESC 2
+#define WBM_INT_ERROR_REO_NULL_MSDU_BUFF 3
+#define WBM_INT_ERROR_REO_BUFF_REAPED 4
+#define MAX_WBM_INT_ERROR_REASONS 5
+
 #define MAX_TX_HW_QUEUES MAX_TCL_DATA_RINGS
 /* Maximum retries for Delba per tid per peer */
 #define DP_MAX_DELBA_RETRY 3
@@ -662,7 +669,7 @@ struct dp_soc_stats {
 		/* tx completion release_src != TQM or FW */
 		uint32_t invalid_release_source;
 		/* tx completion wbm_internal_error */
-		uint32_t wbm_internal_error;
+		uint32_t wbm_internal_error[MAX_WBM_INT_ERROR_REASONS];
 		/* TX Comp loop packet limit hit */
 		uint32_t tx_comp_loop_pkt_limit_hit;
 		/* Head pointer Out of sync at the end of dp_tx_comp_handler */

+ 3 - 0
hal/wifi3.0/hal_tx.h

@@ -29,6 +29,8 @@
 #define WBM_RELEASE_RING_5_TX_RATE_STATS_LSB      0
 #define WBM_RELEASE_RING_5_TX_RATE_STATS_MASK     0xffffffff
 
+#define HAL_WBM_RELEASE_RING_2_BUFFER_TYPE    0
+#define HAL_WBM_RELEASE_RING_2_DESC_TYPE      1
 
 /*---------------------------------------------------------------------------
   Preprocessor definitions and constants
@@ -91,6 +93,7 @@ do {                                            \
 #define HAL_TX_COMPLETION_DESC_BASE_LEN 12
 
 #define HAL_TX_COMP_RELEASE_SOURCE_TQM 0
+#define HAL_TX_COMP_RELEASE_SOURCE_REO 2
 #define HAL_TX_COMP_RELEASE_SOURCE_FW 3
 
 /* Define a place-holder release reason for FW */