From 1746f5b5b62c72131a7d909592c8444594d9726e Mon Sep 17 00:00:00 2001
From: Karthikeyan Kathirvel <kathirve@codeaurora.org>
Date: Mon, 10 Aug 2020 21:41:47 +0530
Subject: [PATCH] ath11k: monitor ring stuck

More than 20000 ppdu id jumping can cause status ring and destination
ring processing not sync. The status ring is processed and the
destination ring is not processed. Since destination is not reaped for
so long, backpressure is occured at destination ring.

Added a workaround to update the ppdu id with the latest ppdu, this will
reap the destination ring and will avoid stuck. Increased monitor ring
sizes to avoid the early backpressure.

Signed-off-by: Karthikeyan Kathirvel <kathirve@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/dp.h    | 10 +++++++++
 drivers/net/wireless/ath/ath11k/dp_rx.c | 36 +++++++++++++++++++++++++++------
 2 files changed, 40 insertions(+), 6 deletions(-)

--- a/drivers/net/wireless/ath/ath11k/dp.h
+++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -101,6 +101,8 @@ struct ath11k_pdev_mon_stats {
 	u32 dest_mpdu_drop;
 	u32 dup_mon_linkdesc_cnt;
 	u32 dup_mon_buf_cnt;
+	u32 dest_mon_stuck;
+	u32 dest_mon_not_reaped;
 };
 
 struct dp_link_desc_bank {
@@ -121,6 +123,13 @@ struct dp_link_desc_bank {
 	(DP_RX_DESC_COOKIE_INDEX_MAX | DP_RX_DESC_COOKIE_POOL_ID_MAX)
 #define DP_NOT_PPDU_ID_WRAP_AROUND 20000
 
+/*
+ * The destination ring processing is stuck if the destination is not
+ * moving while status ring moves 16 ppdu. the destination ring processing
+ * skips this destination ring ppdu as walkaround
+ */
+#define MON_DEST_RING_STUCK_MAX_CNT 16
+
 enum ath11k_dp_ppdu_state {
 	DP_PPDU_STATUS_START,
 	DP_PPDU_STATUS_DONE,
@@ -143,6 +152,7 @@ struct ath11k_mon_data {
 
 struct ath11k_pdev_dp {
 	u32 mac_id;
+	u32 mon_dest_ring_stuck_cnt;
 	atomic_t num_tx_pending;
 	wait_queue_head_t tx_empty_waitq;
 	struct dp_rxdma_ring rx_refill_buf_ring;
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -5426,6 +5426,7 @@ void ath11k_dp_rx_mon_dest_process(struc
 	u32 ring_id;
 	struct ath11k_pdev_mon_stats *rx_mon_stats;
 	u32	 npackets = 0;
+	u32 mpdu_rx_bufs_used;
 
 	if (ar->ab->hw_params.rxdma1_enable)
 		ring_id = dp->rxdma_mon_dst_ring.ring_id;
@@ -5455,10 +5456,29 @@ void ath11k_dp_rx_mon_dest_process(struc
 		head_msdu = NULL;
 		tail_msdu = NULL;
 
-		rx_bufs_used += ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry,
+		mpdu_rx_bufs_used = ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry,
 							  &head_msdu,
 							  &tail_msdu,
 							  &npackets, &ppdu_id);
+		rx_bufs_used += mpdu_rx_bufs_used;
+
+		if (mpdu_rx_bufs_used)
+			dp->mon_dest_ring_stuck_cnt = 0;
+		else {
+			dp->mon_dest_ring_stuck_cnt++;
+			rx_mon_stats->dest_mon_not_reaped++;
+		}
+
+		if (dp->mon_dest_ring_stuck_cnt > MON_DEST_RING_STUCK_MAX_CNT) {
+			rx_mon_stats->dest_mon_stuck++;
+			ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+				   "status ring ppdu_id=%d dest ring ppdu_id=%d mon_dest_ring_stuck_cnt=%d\n" \
+				   "dest_mon_not_reaped=%u dest_mon_stuck=%u",
+				   pmon->mon_ppdu_info.ppdu_id, ppdu_id,dp->mon_dest_ring_stuck_cnt,
+				   rx_mon_stats->dest_mon_not_reaped, rx_mon_stats->dest_mon_stuck);
+			pmon->mon_ppdu_info.ppdu_id = ppdu_id;
+			continue;
+		}
 
 		if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) {
 			pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
