Browse Source

qcacmn: Do not increment tail pointer if no data in CE DST ring

Currently there are cases where the CE status ring
head pointer is incremented, but the corresponding
buffer in the CE DST ring has nbytes as zero. This
can be a possible case where the head pointer was
updated before the DMA copy was completed and before
the nbytes could be updated with the number of bytes
copied to the CE DST ring buffer.In such cases we
haven't processed this entry, and hence should not
increment the tail pointer.

Hence we do not increment the tail pointer if
there was no data in the CE DST ring. Also
enable the logging of CE STATUS RING REAP
even if the CE DST reap was not successful.
This will help identify the cases where the reap
was not successful because of nbytes being zero.

In Success case, the CE desc history will show
STATUS_RING_REAP and DST_RING_REAP events.
In nbytes=0 failure case, the CE desc history will
show STATUS_RING_REAP event with HP moving ahead,
but the TP will not have moved.

Change-Id: Ibc3145142b6c88f6da3e12748d0ac8090486e8e3
CRs-Fixed: 2657285
Rakesh Pillai 5 years ago
parent
commit
e0464a106c
1 changed files with 30 additions and 21 deletions
  1. 30 21
      hif/src/ce/ce_service_srng.c

+ 30 - 21
hif/src/ce/ce_service_srng.c

@@ -417,7 +417,7 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
 	unsigned int nentries_mask = dest_ring->nentries_mask;
 	unsigned int sw_index = dest_ring->sw_index;
 	struct hif_softc *scn = CE_state->scn;
-	struct ce_srng_dest_status_desc *dest_status;
+	struct ce_srng_dest_status_desc *dest_status = NULL;
 	int nbytes;
 	struct ce_srng_dest_status_desc dest_status_info;
 
@@ -426,13 +426,13 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
 		goto done;
 	}
 
-	dest_status = hal_srng_dst_get_next(scn->hal_soc,
-						status_ring->srng_ctx);
-
+	dest_status = hal_srng_dst_peek(scn->hal_soc, status_ring->srng_ctx);
 	if (!dest_status) {
 		status = QDF_STATUS_E_FAILURE;
+		hal_srng_access_end_reap(scn->hal_soc, status_ring->srng_ctx);
 		goto done;
 	}
+
 	/*
 	 * By copying the dest_desc_info element to local memory, we could
 	 * avoid extra memory read from non-cachable memory.
@@ -440,16 +440,28 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
 	dest_status_info = *dest_status;
 	nbytes = dest_status_info.nbytes;
 	if (nbytes == 0) {
+		uint32_t hp, tp;
+
 		/*
 		 * This closes a relatively unusual race where the Host
 		 * sees the updated DRRI before the update to the
 		 * corresponding descriptor has completed. We treat this
 		 * as a descriptor that is not yet done.
 		 */
+		hal_get_sw_hptp(scn->hal_soc, status_ring->srng_ctx,
+				&hp, &tp);
+		hif_info("No data to reap, hp %d tp %d", hp, tp);
 		status = QDF_STATUS_E_FAILURE;
+		hal_srng_access_end_reap(scn->hal_soc, status_ring->srng_ctx);
 		goto done;
 	}
 
+	/*
+	 * Move the tail pointer since nbytes is non-zero and
+	 * this entry is processed.
+	 */
+	hal_srng_dst_get_next(scn->hal_soc, status_ring->srng_ctx);
+
 	dest_status->nbytes = 0;
 
 	*nbytesp = nbytes;
@@ -474,25 +486,22 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
 	dest_ring->sw_index = sw_index;
 	status = QDF_STATUS_SUCCESS;
 
-done:
 	hal_srng_access_end(scn->hal_soc, status_ring->srng_ctx);
+	hif_record_ce_srng_desc_event(scn, CE_state->id,
+				      HIF_CE_DEST_RING_BUFFER_REAP,
+				      NULL,
+				      dest_ring->
+				      per_transfer_context[sw_index],
+				      dest_ring->sw_index, nbytes,
+				      dest_ring->srng_ctx);
 
-	if (status == QDF_STATUS_SUCCESS) {
-		hif_record_ce_srng_desc_event(scn, CE_state->id,
-					      HIF_CE_DEST_RING_BUFFER_REAP,
-					      NULL,
-					      dest_ring->
-					      per_transfer_context[sw_index],
-					      dest_ring->sw_index, nbytes,
-					      dest_ring->srng_ctx);
-
-		hif_record_ce_srng_desc_event(scn, CE_state->id,
-					      HIF_CE_DEST_STATUS_RING_REAP,
-					      (union ce_srng_desc *)dest_status,
-					      NULL,
-					      -1, 0,
-					      status_ring->srng_ctx);
-	}
+done:
+	hif_record_ce_srng_desc_event(scn, CE_state->id,
+				      HIF_CE_DEST_STATUS_RING_REAP,
+				      (union ce_srng_desc *)dest_status,
+				      NULL,
+				      -1, 0,
+				      status_ring->srng_ctx);
 
 	return status;
 }