Browse Source

qcacmn: Handle duplicate pkt desc in wkk monitor path

Sometimes we receive duplicate packet buffer descriptors.
This results in corruption of descriptor freelist.
Add check to handle duplicate packet monitor descriptors.

Change-Id: I1dd33575fba78a7816063c40bf29ba41f9bcf226
CRs-Fixed: 3519326
Jeevan Kukkalli 2 years ago
parent
commit
aa280d43e6
2 changed files with 55 additions and 0 deletions
  1. 4 0
      dp/wifi3.0/monitor/2.0/dp_mon_2.0.h
  2. 51 0
      dp/wifi3.0/monitor/2.0/dp_rx_mon_2.0.c

+ 4 - 0
dp/wifi3.0/monitor/2.0/dp_mon_2.0.h

@@ -236,6 +236,8 @@ struct dp_mon_desc_pool {
  * @lite_mon_tx_config: tx litemon config
  * @prev_rxmon_desc: prev destination desc
  * @prev_rxmon_cookie: prev rxmon cookie
+ * @prev_rxmon_pkt_desc: prev packet buff desc
+ * @prev_rxmon_pkt_cookie: prev packet buff desc cookie
  * @ppdu_info_cache: PPDU info cache
  * @total_free_elem: total free element in queue
  * @rx_tlv_logger: Rx TLV logger struct
@@ -263,6 +265,8 @@ struct dp_mon_pdev_be {
 #endif
 	void *prev_rxmon_desc;
 	uint32_t prev_rxmon_cookie;
+	void *prev_rxmon_pkt_desc;
+	uint32_t prev_rxmon_pkt_cookie;
 	qdf_kmem_cache_t ppdu_info_cache;
 	uint32_t total_free_elem;
 #ifdef MONITOR_TLV_RECORDING_ENABLE

+ 51 - 0
dp/wifi3.0/monitor/2.0/dp_rx_mon_2.0.c

@@ -1245,6 +1245,8 @@ dp_rx_mon_flush_packet_tlv(struct dp_pdev *pdev, void *buf, uint16_t end_offset,
 {
 	struct dp_soc *soc = pdev->soc;
 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
+	struct dp_mon_pdev_be *mon_pdev_be =
+			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
 	uint16_t work_done = 0;
 	qdf_frag_t addr;
@@ -1275,6 +1277,23 @@ dp_rx_mon_flush_packet_tlv(struct dp_pdev *pdev, void *buf, uint16_t end_offset,
 			struct dp_mon_desc *mon_desc = (struct dp_mon_desc *)(uintptr_t)ppdu_info->packet_info.sw_cookie;
 
 			qdf_assert_always(mon_desc);
+
+			/* WAR: sometimes duplicate pkt desc are received
+			 * from HW, this check gracefully handles
+			 * such cases.
+			 */
+			if ((mon_desc == mon_pdev_be->prev_rxmon_pkt_desc) &&
+			    (mon_desc->cookie ==
+			     mon_pdev_be->prev_rxmon_pkt_cookie)) {
+				dp_mon_err("duplicate pkt desc found mon_pdev: %pK mon_desc: %pK cookie: %d",
+					   mon_pdev, mon_desc,
+					   mon_desc->cookie);
+				mon_pdev->rx_mon_stats.dup_mon_buf_cnt++;
+				goto end;
+			}
+			mon_pdev_be->prev_rxmon_pkt_desc = mon_desc;
+			mon_pdev_be->prev_rxmon_pkt_cookie = mon_desc->cookie;
+
 			addr = mon_desc->buf_addr;
 
 			if (!mon_desc->unmapped) {
@@ -1293,6 +1312,7 @@ dp_rx_mon_flush_packet_tlv(struct dp_pdev *pdev, void *buf, uint16_t end_offset,
 			}
 		}
 
+end:
 		rx_tlv = hal_rx_status_get_next_tlv(rx_tlv, 1);
 
 		if ((rx_tlv - rx_tlv_start) >= (end_offset + 1))
@@ -1363,6 +1383,8 @@ dp_rx_mon_flush_status_buf_queue(struct dp_pdev *pdev)
 		qdf_frag_free(buf);
 		DP_STATS_INC(mon_soc, frag_free, 1);
 	}
+	mon_pdev_be->prev_rxmon_pkt_desc = NULL;
+	mon_pdev_be->prev_rxmon_pkt_cookie = 0;
 
 	if (work_done) {
 		mon_pdev->rx_mon_stats.mon_rx_bufs_replenished_dest +=
@@ -1386,6 +1408,9 @@ dp_rx_mon_handle_flush_n_trucated_ppdu(struct dp_soc *soc,
 				       struct dp_pdev *pdev,
 				       struct dp_mon_desc *mon_desc)
 {
+	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
+	struct dp_mon_pdev_be *mon_pdev_be =
+			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
 	union dp_mon_desc_list_elem_t *desc_list = NULL;
 	union dp_mon_desc_list_elem_t *tail = NULL;
 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
@@ -1408,6 +1433,10 @@ dp_rx_mon_handle_flush_n_trucated_ppdu(struct dp_soc *soc,
 		qdf_frag_free(buf);
 		DP_STATS_INC(mon_soc, frag_free, 1);
 	}
+
+	mon_pdev_be->prev_rxmon_desc = NULL;
+	mon_pdev_be->prev_rxmon_cookie = 0;
+
 	if (desc_list)
 		dp_mon_add_desc_list_to_free_list(soc, &desc_list, &tail,
 						  rx_mon_desc_pool);
@@ -1443,6 +1472,8 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 	struct dp_soc *soc  = pdev->soc;
 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
+	struct dp_mon_pdev_be *mon_pdev_be =
+			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
 	qdf_nbuf_t nbuf, tmp_nbuf;
 	qdf_frag_t addr;
 	uint8_t user_id = ppdu_info->user_id;
@@ -1553,6 +1584,22 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
 		if (mon_desc->magic != DP_MON_DESC_MAGIC)
 			qdf_assert_always(0);
 
+		/* WAR: sometimes duplicate pkt desc are received
+		 * from HW this check gracefully handles
+		 * such cases.
+		 */
+		if ((mon_desc == mon_pdev_be->prev_rxmon_pkt_desc) &&
+		    (mon_desc->cookie ==
+		     mon_pdev_be->prev_rxmon_pkt_cookie)) {
+			dp_mon_err("duplicate pkt desc found mon_pdev: %pK mon_desc: %pK cookie: %d",
+				   mon_pdev, mon_desc,
+				   mon_desc->cookie);
+			mon_pdev->rx_mon_stats.dup_mon_buf_cnt++;
+			return num_buf_reaped;
+		}
+		mon_pdev_be->prev_rxmon_pkt_desc = mon_desc;
+		mon_pdev_be->prev_rxmon_pkt_cookie = mon_desc->cookie;
+
 		addr = mon_desc->buf_addr;
 		qdf_assert_always(addr);
 
@@ -1889,6 +1936,10 @@ dp_rx_mon_process_status_tlv(struct dp_pdev *pdev)
 		mon_pdev->rx_mon_stats.status_buf_count++;
 		dp_mon_record_index_update(mon_pdev_be);
 	}
+	mon_pdev_be->prev_rxmon_desc = NULL;
+	mon_pdev_be->prev_rxmon_cookie = 0;
+	mon_pdev_be->prev_rxmon_pkt_desc = NULL;
+	mon_pdev_be->prev_rxmon_pkt_cookie = 0;
 
 	dp_mon_rx_stats_update_rssi_dbm_params(mon_pdev, ppdu_info);
 	if (work_done) {