Bladeren bron

Merge "qca-wifi: Fix ppdu_id mismatch issue"

Linux Build Service Account 5 jaren geleden
bovenliggende
commit
0d19542bc1
2 gewijzigde bestanden met toevoegingen van 212 en 117 verwijderingen
  1. 195 117
      dp/wifi3.0/dp_full_mon.c
  2. 17 0
      dp/wifi3.0/dp_full_mon.h

+ 195 - 117
dp/wifi3.0/dp_full_mon.c

@@ -43,7 +43,7 @@ dp_rx_mon_status_process(struct dp_soc *soc,
  *
  * Return: QDF_STATUS
  */
-static inline QDF_STATUS
+static inline enum dp_mon_reap_status
 dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 {
 	struct dp_soc *soc = pdev->soc;
@@ -58,8 +58,9 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 	uint32_t tlv_tag;
 	void *rx_tlv;
 	struct hal_rx_ppdu_info *ppdu_info;
-	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	enum dp_mon_reap_status status = dp_mon_status_match;
 	QDF_STATUS buf_status;
+	uint32_t ppdu_id_diff;
 
 	mon_status_srng = soc->rxdma_mon_status_ring[mac_id].hal_srng;
 
@@ -85,8 +86,9 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 	ring_entry = hal_srng_src_peek_n_get_next(hal_soc, mon_status_srng);
 	if (!ring_entry) {
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"%s %d : HAL SRNG entry is NULL srng:-- %pK",
-			__func__, __LINE__, mon_status_srng);
+			  "%s %d : HAL SRNG entry is NULL srng:-- %pK",
+			  __func__, __LINE__, mon_status_srng);
+		status = dp_mon_status_replenish;
 		goto done;
 	}
 
@@ -101,6 +103,7 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 			  "%s %d : buf addr is NULL -- %pK",
 			  __func__, __LINE__, mon_status_srng);
+		status = dp_mon_status_replenish;
 		goto done;
 	}
 
@@ -127,7 +130,7 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 			     "for nbuf: %pK buf_addr: %llx"),
 			     status_nbuf, buf_paddr);
 		pdev->rx_mon_stats.tlv_tag_status_err++;
-		pdev->hold_mon_dest_ring = true;
+		status = dp_mon_status_no_dma;
 		goto done;
 	}
 
@@ -147,17 +150,23 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 		pdev->status_buf_addr = buf_paddr;
 	}
 
-	/* If Monitor destination ring is on hold and ppdu id matches,
-	 * deliver PPDU data which was on hold.
-	 */
-	if (pdev->hold_mon_dest_ring &&
-	    (pdev->mon_desc->ppdu_id == pdev->ppdu_info.com_info.ppdu_id)) {
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			  FL("Monitor destination was on Hold "
-			     "PPDU id matched"));
+	if (pdev->mon_desc->ppdu_id < pdev->ppdu_info.com_info.ppdu_id) {
+		status = dp_mon_status_lead;
 
-		pdev->hold_mon_dest_ring = false;
-		goto done;
+		/* For wrap around case */
+		ppdu_id_diff = pdev->ppdu_info.com_info.ppdu_id -
+			       pdev->mon_desc->ppdu_id;
+
+		if (ppdu_id_diff > DP_RX_MON_PPDU_ID_WRAP)
+			status = dp_mon_status_lag;
+
+	} else if (pdev->mon_desc->ppdu_id > pdev->ppdu_info.com_info.ppdu_id) {
+		status = dp_mon_status_lag;
+		/* For wrap around case */
+		ppdu_id_diff = pdev->mon_desc->ppdu_id -
+			       pdev->ppdu_info.com_info.ppdu_id;
+		if (ppdu_id_diff > DP_RX_MON_PPDU_ID_WRAP)
+			status = dp_mon_status_lead;
 	}
 
 	if ((pdev->mon_desc->status_buf.paddr != buf_paddr) ||
@@ -167,45 +176,12 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
 			     "status_ppdu_id: %d dest_ppdu_id: %d "
 			     "status_addr: %llx status_buf_cookie: %d "
 			     "dest_addr: %llx tlv_tag: %d"
-			     " status_nbuf: %pK"),
+			     " status_nbuf: %pK pdev->hold_mon_dest: %d"),
 			      pdev->ppdu_info.com_info.ppdu_id,
 			      pdev->mon_desc->ppdu_id, pdev->status_buf_addr,
 			      rx_buf_cookie,
 			      pdev->mon_desc->status_buf.paddr, tlv_tag,
-			      status_nbuf);
-	}
-
-	/* Monitor Status ring is reaped in two cases:
-	 * a. If first status buffer's buf_addr_info matches
-	 * with latched status buffer addr info in monitor
-	 * destination ring.
-	 * b. If monitor status ring is lagging behind
-	 * monitor destination ring. Hold on to monitor
-	 * destination ring in this case until status ring
-	 * and destination ring ppdu id matches.
-	 */
-	if ((pdev->mon_desc->status_buf.paddr == buf_paddr) ||
-	    (pdev->mon_desc->ppdu_id > pdev->ppdu_info.com_info.ppdu_id)) {
-		if (pdev->mon_desc->ppdu_id >
-		    pdev->ppdu_info.com_info.ppdu_id) {
-
-			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-				  FL("Monitor status ring is lagging behind "
-				     "monitor destination ring "
-				     "status_ppdu_id: %d dest_ppdu_id: %d "
-				     "status_nbuf: %pK tlv_tag: %d "
-				     "status_addr: %llx dest_addr: %llx "),
-				     ppdu_info->com_info.ppdu_id,
-				     pdev->mon_desc->ppdu_id,
-				     status_nbuf, tlv_tag,
-				     pdev->status_buf_addr,
-				     pdev->mon_desc->status_buf.paddr);
-
-			pdev->rx_mon_stats.ppdu_id_mismatch++;
-			pdev->rx_mon_stats.status_ppdu_drop++;
-			pdev->hold_mon_dest_ring = true;
-		}
-		status = QDF_STATUS_SUCCESS;
+			      status_nbuf, pdev->hold_mon_dest_ring);
 	}
 done:
 	hal_srng_access_end(hal_soc, mon_status_srng);
@@ -279,6 +255,7 @@ dp_rx_mon_drop_ppdu(struct dp_pdev *pdev, uint32_t mac_id)
 			qdf_mem_free(mpdu);
 		}
 	}
+	pdev->mon_desc->drop_ppdu = 0;
 }
 
 /*
@@ -338,41 +315,69 @@ dp_rx_mon_reap_status_ring(struct dp_soc *soc,
 	struct dp_pdev *pdev = dp_get_pdev_for_lmac_id(soc, mac_id);
 	uint8_t status_buf_count;
 	uint32_t work_done = 0;
+	enum dp_mon_reap_status status;
 
 	status_buf_count = desc_info->status_buf_count;
 	desc_info->drop_ppdu = false;
 
-	if (dp_rx_mon_status_buf_validate(pdev, mac_id) == QDF_STATUS_SUCCESS)
-		work_done = dp_rx_mon_status_process(soc,
-						     mac_id,
-						     status_buf_count);
-
-	if (desc_info->ppdu_id != pdev->ppdu_info.com_info.ppdu_id) {
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			  FL("Monitor: PPDU id mismatch "
-			     "status_ppdu_id: %d dest_ppdu_id: %d "
-			     "status_addr: %llx dest_addr: %llx "
-			     "count: %d quota: %d work_done: %d "),
-			      pdev->ppdu_info.com_info.ppdu_id,
-			      pdev->mon_desc->ppdu_id, pdev->status_buf_addr,
-			      pdev->mon_desc->status_buf.paddr,
-			       status_buf_count, quota, work_done);
+	status = dp_rx_mon_status_buf_validate(pdev, mac_id);
+	switch (status) {
+		case dp_mon_status_no_dma:
+			/* If DMA is not done for status ring entry,
+			 * hold on to monitor destination ring and
+			 * deliver current ppdu data once DMA is done.
+			 */
+			pdev->hold_mon_dest_ring = true;
+			break;
+		case dp_mon_status_lag:
+			/* If status_ppdu_id is lagging behind destination,
+			 * a. Hold on to destination ring
+			 * b. Drop status ppdus until ppdu id matches
+			 * c. Increment stats for ppdu_id mismatch and
+			 *    status ppdu drop
+			 */
+			pdev->hold_mon_dest_ring = true;
+			pdev->rx_mon_stats.ppdu_id_mismatch++;
+			pdev->rx_mon_stats.status_ppdu_drop++;
+			break;
+		case dp_mon_status_lead:
+			/* If status_ppdu_id is leading ahead destination,
+			 * a. Drop destination ring ppdu until ppdu_id matches
+			 * b. Unhold monitor destination ring so status ppdus
+			 *    can be dropped.
+			 * c. Increment stats for ppdu_id mismatch and
+			 *    destination ppdu drop
+			 */
+			desc_info->drop_ppdu = true;
+			pdev->hold_mon_dest_ring = false;
+			pdev->rx_mon_stats.ppdu_id_mismatch++;
+			pdev->rx_mon_stats.dest_ppdu_drop++;
+			break;
+		case dp_mon_status_replenish:
+			/* If status ring hp entry is NULL, replenish it */
+			work_done = dp_rx_mon_status_process(soc, mac_id, 1);
+			break;
+		case dp_mon_status_match:
+			/* If status ppdu id matches with destnation,
+			 * unhold monitor destination ring and deliver ppdu
+			 */
+			pdev->hold_mon_dest_ring = false;
+			break;
+		default:
+			dp_err("mon reap status is not supported");
 	}
 
-	if (desc_info->ppdu_id < pdev->ppdu_info.com_info.ppdu_id) {
-		pdev->rx_mon_stats.ppdu_id_mismatch++;
-		desc_info->drop_ppdu = true;
-		pdev->rx_mon_stats.dest_ppdu_drop++;
+	/* If status ring is lagging behind detination ring,
+	 * reap only one status buffer
+	 */
+	if (status == dp_mon_status_lag)
+		status_buf_count = 1;
 
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			  FL("Monitor destination ring is lagging behind "
-			     "monitor status ring "
-			     "status_ppdu_id: %d dest_ppdu_id: %d "
-			     "status_addr: %llx dest_addr: %llx "),
-			     pdev->ppdu_info.com_info.ppdu_id,
-			     pdev->mon_desc->ppdu_id,
-			     pdev->status_buf_addr,
-			     pdev->mon_desc->status_buf.paddr);
+	if (status == dp_mon_status_lag ||
+	    status == dp_mon_status_match) {
+		work_done = dp_rx_mon_status_process(soc,
+						     mac_id,
+						     status_buf_count);
 	}
 
 	return work_done;
@@ -594,44 +599,92 @@ dp_rx_mon_deliver_prev_ppdu(struct dp_pdev *pdev,
 
 	struct dp_soc *soc = pdev->soc;
 	struct hal_rx_mon_desc_info *desc_info = pdev->mon_desc;
-	uint32_t work_done = 0;
-	bool hold_mon_dest_ring = false;
+	uint32_t work_done = 0, work = 0;
+	bool deliver_ppdu = false;
+	enum dp_mon_reap_status status;
 
 	while (pdev->hold_mon_dest_ring) {
-		if (dp_rx_mon_status_buf_validate(pdev, mac_id) == QDF_STATUS_SUCCESS) {
-			work_done = dp_rx_mon_status_process(soc, mac_id, 1);
+		status = dp_rx_mon_status_buf_validate(pdev, mac_id);
+
+		switch (status) {
+			case dp_mon_status_no_dma:
+			/* If DMA is not done for status ring entry,
+			 * hold on to monitor destination ring and
+			 * deliver current ppdu data once DMA is done.
+			 */
+			pdev->hold_mon_dest_ring = true;
+			break;
+			case dp_mon_status_lag:
+			/* If status_ppdu_id is lagging behind destination,
+			 * a. Hold on to destination ring
+			 * b. Drop status ppdus until ppdu id matches
+			 * c. Increment stats for ppdu_id mismatch and
+			 *    status ppdu drop
+			 */
+			pdev->hold_mon_dest_ring = true;
+			pdev->rx_mon_stats.ppdu_id_mismatch++;
+			pdev->rx_mon_stats.status_ppdu_drop++;
+			break;
+			case dp_mon_status_lead:
+			/* If status_ppdu_id is leading ahead destination,
+			 * a. Drop destination ring ppdu until ppdu_id matches
+			 * b. Unhold monitor destination ring so status ppdus
+			 *    can be dropped.
+			 * c. Increment stats for ppdu_id mismatch and
+			 *    destination ppdu drop
+			 */
+			desc_info->drop_ppdu = true;
+			pdev->hold_mon_dest_ring = false;
+			pdev->rx_mon_stats.ppdu_id_mismatch++;
+			pdev->rx_mon_stats.dest_ppdu_drop++;
+			break;
+			case dp_mon_status_replenish:
+			/* If status ring hp entry is NULL, replenish it */
+			work = dp_rx_mon_status_process(soc, mac_id, 1);
+			break;
+			case dp_mon_status_match:
+			/* If status ppdu id matches with destnation,
+			 * unhold monitor destination ring and deliver ppdu
+			 */
+			pdev->hold_mon_dest_ring = false;
+			break;
+			default:
+				dp_err("mon reap status is not supported");
 		}
-		quota -= work_done;
 
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			  FL("Hold on Monitor destination ring "
-			      "work_done: %d quota: %d status_ppdu_id: %d "
-			      "dest_ppdu_id: %d s_addr: %llx d_addr: %llx "),
-			      work_done, quota,
-			      pdev->ppdu_info.com_info.ppdu_id,
-			      desc_info->ppdu_id, pdev->status_buf_addr,
-			      desc_info->status_buf.paddr);
+		/* When status ring entry's DMA is not done or
+		 * status ring entry is replenished, ppdu status is not
+		 * available for radiotap construction, so return and
+		 * check for status on next interrupt
+		 */
+		if ((status == dp_mon_status_no_dma) ||
+		    (status == dp_mon_status_replenish)) {
+			return work_done;
+		}
+
+		if (status == dp_mon_status_lag) {
+			work = dp_rx_mon_status_process(soc, mac_id, 1);
 
-		hold_mon_dest_ring = true;
+			if (!work)
+				return 0;
 
-		if (!quota)
-			return quota;
+			work_done += work;
+		}
+		deliver_ppdu = true;
 	}
-	if (hold_mon_dest_ring) {
-		if (quota >= desc_info->status_buf_count) {
-			qdf_err("DEBUG:");
-			work_done = dp_rx_mon_status_process(soc, mac_id,
-							     desc_info->status_buf_count);
-			dp_rx_monitor_deliver_ppdu(soc, mac_id);
-			hold_mon_dest_ring = false;
-		} else {
-			pdev->hold_mon_dest_ring = true;
-			return quota;
+
+	if (deliver_ppdu) {
+		if (pdev->mon_desc->drop_ppdu) {
+			dp_rx_mon_drop_ppdu(pdev, mac_id);
+			return work_done;
 		}
-		quota -= work_done;
+
+		work_done += dp_rx_mon_status_process(soc, mac_id,
+				desc_info->status_buf_count);
+		dp_rx_monitor_deliver_ppdu(soc, mac_id);
 	}
 
-	return quota;
+	return work_done;
 }
 
 /**
@@ -653,7 +706,7 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 	union dp_rx_desc_list_elem_t *tail_desc = NULL;
 	uint32_t rx_bufs_reaped = 0;
 	struct dp_mon_mpdu *mon_mpdu;
-	struct cdp_pdev_mon_stats *rx_mon_stats = &pdev->rx_mon_stats;
+	struct cdp_pdev_mon_stats *rx_mon_stats;
 	hal_rxdma_desc_t ring_desc;
 	hal_soc_handle_t hal_soc;
 	hal_ring_handle_t mon_dest_srng;
@@ -664,28 +717,36 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 	QDF_STATUS status;
 	uint32_t work_done = 0;
 
+	if (!pdev) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			  "pdev is null for mac_id = %d", mac_id);
+		return work_done;
+	}
+
 	qdf_spin_lock_bh(&pdev->mon_lock);
 	if (qdf_unlikely(!dp_soc_is_full_mon_enable(pdev))) {
-		quota -= dp_rx_mon_status_process(soc, mac_id, quota);
+		work_done += dp_rx_mon_status_process(soc, mac_id, quota);
 		qdf_spin_unlock_bh(&pdev->mon_lock);
-		return quota;
+		return work_done;
 	}
 
 	desc_info = pdev->mon_desc;
 
-	quota = dp_rx_mon_deliver_prev_ppdu(pdev, mac_id, quota);
+	rx_mon_stats = &pdev->rx_mon_stats;
 
-	/* Do not proceed if quota expires */
-	if (!quota || pdev->hold_mon_dest_ring) {
+	work_done = dp_rx_mon_deliver_prev_ppdu(pdev, mac_id, quota);
+
+	/* Do not proceed if work_done zero */
+	if (!work_done && pdev->hold_mon_dest_ring) {
 		qdf_spin_unlock_bh(&pdev->mon_lock);
-		return quota;
+		return work_done;
 	}
 
 	mon_dest_srng = dp_rxdma_get_mon_dst_ring(pdev, mac_for_pdev);
 
 	if (qdf_unlikely(!mon_dest_srng ||
 			 !hal_srng_initialized(mon_dest_srng))) {
-		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 			  FL("HAL Monitor Destination Ring Init Failed -- %pK"),
 			  mon_dest_srng);
 		goto done1;
@@ -791,6 +852,23 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 			continue;
 		}
 
+		/* It is observed sometimes that, ppdu_id, status_buf_addr
+		 * and link desc addr is NULL, this WAR is to handle same
+		 */
+
+		if (!desc_info->ppdu_id && !desc_info->status_buf.paddr) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+				  FL("ppdu_id: %d ring_entry: %pK"
+				     "status_buf_count: %d rxdma_push: %d"
+				     "rxdma_err: %d link_desc: %pK "),
+				  desc_info->ppdu_id, ring_desc,
+				  desc_info->status_buf_count,
+				  desc_info->rxdma_push_reason,
+				  desc_info->rxdma_error_code,
+				  desc_info->link_desc.paddr);
+			goto next_entry;
+		}
+
 		/*
 		 * end_of_ppdu is one,
 		 *  a. update ppdu_done stattistics
@@ -800,7 +878,7 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 		 */
 		rx_mon_stats->dest_ppdu_done++;
 
-		work_done = dp_rx_mon_reap_status_ring(soc, mac_id,
+		work_done += dp_rx_mon_reap_status_ring(soc, mac_id,
 							quota, desc_info);
 		/* Deliver all MPDUs for a PPDU */
 		if (desc_info->drop_ppdu)
@@ -808,8 +886,8 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 		else if (!pdev->hold_mon_dest_ring)
 			dp_rx_monitor_deliver_ppdu(soc, mac_id);
 
+next_entry:
 		hal_srng_dst_get_next(hal_soc, mon_dest_srng);
-		quota -= work_done;
 		break;
 	}
 
@@ -818,7 +896,7 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 done1:
 	qdf_spin_unlock_bh(&pdev->mon_lock);
 
-	return quota;
+	return work_done;
 }
 
 /**

+ 17 - 0
dp/wifi3.0/dp_full_mon.h

@@ -17,6 +17,7 @@
 #ifndef _DP_FULL_MON_H_
 #define _DP_FULL_MON_H_
 
+#define DP_RX_MON_PPDU_ID_WRAP 32535
 /**
  * struct dp_mon_mpdu () - DP Monitor mpdu object
  *
@@ -57,4 +58,20 @@ dp_rx_mon_is_rxdma_error(struct hal_rx_mon_desc_info *desc_info)
 	return QDF_STATUS_E_FAILURE;
 }
 
+/*
+ * dp_mon_reap_status - monitor status ring ppdu status
+ *
+ * dp_mon_status_no_dma - DMA not done for status ring entry
+ * dp_mon_status_match - status and dest ppdu id mathes
+ * dp_mon_status_lag - status ppdu id is lagging
+ * dp_mon_status_lead - status ppdu id is leading
+ * dp_mon_status_replenish - status ring entry is NULL
+ */
+enum dp_mon_reap_status {
+	dp_mon_status_no_dma,
+	dp_mon_status_match,
+	dp_mon_status_lag,
+	dp_mon_status_lead,
+	dp_mon_status_replenish
+};
 #endif /* _DP_FULL_MON_H_ */