Browse Source

qcacmn: Release link descriptors on defrag errors

Link descriptors should be returned to WBM release ring if
fragments are not reinjected due to defrag errors.

Change-Id: Ia37db9f195f6848092918cf7cc221dc50e827ac5
Karunakar Dasineni 6 years ago
parent
commit
6fb46e2759
3 changed files with 44 additions and 10 deletions
  1. 2 0
      dp/wifi3.0/dp_main.c
  2. 38 10
      dp/wifi3.0/dp_rx_defrag.c
  3. 4 0
      dp/wifi3.0/dp_types.h

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

@@ -6389,6 +6389,8 @@ dp_print_soc_rx_stats(struct dp_soc *soc)
 	DP_PRINT_STATS("HAL Ring Access Fail = %d",
 			soc->stats.rx.err.hal_ring_access_fail);
 	DP_PRINT_STATS("RX frags: %d", soc->stats.rx.rx_frags);
+	DP_PRINT_STATS("RX frag wait: %d", soc->stats.rx.rx_frag_wait);
+	DP_PRINT_STATS("RX frag err: %d", soc->stats.rx.rx_frag_err);
 	DP_PRINT_STATS("RX HP out_of_sync: %d", soc->stats.rx.hp_oos);
 
 	for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) {

+ 38 - 10
dp/wifi3.0/dp_rx_defrag.c

@@ -23,6 +23,7 @@
 #include "hal_api.h"
 #include "qdf_trace.h"
 #include "qdf_nbuf.h"
+#include "dp_internal.h"
 #include "dp_rx_defrag.h"
 #include <enet.h>	/* LLC_SNAP_HDR_LEN */
 #include "dp_rx_defrag.h"
@@ -182,6 +183,7 @@ void dp_rx_defrag_waitlist_flush(struct dp_soc *soc)
 
 		TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder,
 			     defrag_waitlist_elem);
+		DP_STATS_DEC(soc, rx.rx_frag_wait, 1);
 
 		/* Move to temp list and clean-up later */
 		TAILQ_INSERT_TAIL(&temp_list, rx_reorder,
@@ -226,6 +228,7 @@ static void dp_rx_defrag_waitlist_add(struct dp_peer *peer, unsigned tid)
 	qdf_spin_lock_bh(&psoc->rx.defrag.defrag_lock);
 	TAILQ_INSERT_TAIL(&psoc->rx.defrag.waitlist, rx_reorder,
 				defrag_waitlist_elem);
+	DP_STATS_INC(psoc, rx.rx_frag_wait, 1);
 	qdf_spin_unlock_bh(&psoc->rx.defrag.defrag_lock);
 }
 
@@ -262,9 +265,11 @@ void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid)
 				     rx_tid[rx_reorder->tid]);
 
 		/* Ensure it is TID for same peer */
-		if (peer_on_waitlist == peer && rx_reorder->tid == tid)
+		if (peer_on_waitlist == peer && rx_reorder->tid == tid) {
 			TAILQ_REMOVE(&soc->rx.defrag.waitlist,
 				rx_reorder, defrag_waitlist_elem);
+			DP_STATS_DEC(soc, rx.rx_frag_wait, 1);
+		}
 	}
 	qdf_spin_unlock_bh(&soc->rx.defrag.defrag_lock);
 }
@@ -1384,7 +1389,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 		dp_rx_add_to_free_desc_list(head, tail, rx_desc);
 		*rx_bfs = 1;
 
-		return QDF_STATUS_E_DEFRAG_ERROR;
+		goto end;
 	}
 
 	pdev = peer->vdev->pdev;
@@ -1458,11 +1463,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 			/* Drop stored fragments if out of sequence
 			 * fragment is received
 			 */
-			dp_rx_defrag_frames_free(rx_reorder_array_elem->head);
-
-			rx_reorder_array_elem->head = NULL;
-			rx_reorder_array_elem->tail = NULL;
+			dp_rx_reorder_flush_frag(peer, tid);
 
+			DP_STATS_INC(soc, rx.rx_frag_err, 1);
 			QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
 				"%s mismatch, dropping earlier sequence ",
 				(rxseq == rx_tid->curr_seq_num)
@@ -1474,7 +1477,6 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 			 * new sequence number to be processed
 			 */
 			rx_tid->curr_seq_num = rxseq;
-
 		}
 	} else {
 		/* Start of a new sequence */
@@ -1584,8 +1586,10 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 	return QDF_STATUS_SUCCESS;
 
 end:
-	dp_peer_unref_del_find_by_id(peer);
+	if (peer)
+		dp_peer_unref_del_find_by_id(peer);
 
+	DP_STATS_INC(soc, rx.rx_frag_err, 1);
 	return QDF_STATUS_E_DEFRAG_ERROR;
 }
 
@@ -1621,7 +1625,8 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
 	uint32_t tid, msdu_len;
 	int idx, rx_bfs = 0;
 	struct dp_pdev *pdev;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct dp_rx_desc *rx_desc = NULL;
 
 	qdf_assert(soc);
 	qdf_assert(mpdu_desc_info);
@@ -1649,7 +1654,7 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
 			     &mpdu_desc_info->msdu_count);
 
 	/* Process all MSDUs in the current MPDU */
-	for (idx = 0; (idx < mpdu_desc_info->msdu_count) && quota--; idx++) {
+	for (idx = 0; (idx < mpdu_desc_info->msdu_count); idx++) {
 		struct dp_rx_desc *rx_desc =
 			dp_rx_cookie_2_va_rxdma_buf(soc,
 				msdu_list.sw_cookie[idx]);
@@ -1698,6 +1703,29 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
 		}
 	}
 
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		/* drop any remaining buffers in current descriptor */
+		idx++;
+		for (; (idx < mpdu_desc_info->msdu_count); idx++) {
+			rx_desc =
+				dp_rx_cookie_2_va_rxdma_buf(soc,
+							    msdu_list.sw_cookie[idx]);
+			qdf_assert(rx_desc);
+			msdu = rx_desc->nbuf;
+			qdf_nbuf_unmap_single(soc->osdev, msdu,
+					      QDF_DMA_BIDIRECTIONAL);
+			qdf_nbuf_free(msdu);
+			dp_rx_add_to_free_desc_list(&pdev->free_list_head,
+						    &pdev->free_list_tail,
+						    rx_desc);
+			rx_bufs_used++;
+		}
+		if (dp_rx_link_desc_return(soc, ring_desc,
+					   HAL_BM_ACTION_PUT_IN_IDLE_LIST) !=
+					   QDF_STATUS_SUCCESS)
+			dp_err("Failed to return link desc");
+	}
+
 	return rx_bufs_used;
 }
 

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

@@ -592,6 +592,10 @@ struct dp_soc_stats {
 		uint32_t err_ring_pkts;
 		/* No of Fragments */
 		uint32_t rx_frags;
+		/* No of incomplete fragments in waitlist */
+		uint32_t rx_frag_wait;
+		/* Fragments dropped due to errors */
+		uint32_t rx_frag_err;
 		/* No of reinjected packets */
 		uint32_t reo_reinject;
 		/* Head pointer Out of sync */