Эх сурвалжийг харах

qcacmn: Free cloned nbufs in error condition

While sending me packets, if failure is encountered
either while preparing tx desc or while enqueuing
to h/w,the cloned nbuf's must be freed.The unmap
must be done only if the failure is encountered
for all the me buffers.

Change-Id: I08dbae1fa1820b4fb31119f65e939aead829321b
Debasis Das 4 жил өмнө
parent
commit
82de94ec39
1 өөрчлөгдсөн 47 нэмэгдсэн , 0 устгасан
  1. 47 0
      dp/wifi3.0/dp_tx.c

+ 47 - 0
dp/wifi3.0/dp_tx.c

@@ -2009,6 +2009,7 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 	uint16_t htt_tcl_metadata = 0;
 	struct dp_tx_queue *tx_q = &msdu_info->tx_queue;
 	struct cdp_tid_tx_stats *tid_stats = NULL;
+	uint8_t prep_desc_fail = 0, hw_enq_fail = 0;
 
 	if (qdf_unlikely(soc->cce_disable)) {
 		is_cce_classified = dp_cce_classify(vdev, nbuf);
@@ -2037,9 +2038,32 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 
 		if (!tx_desc) {
 			if (msdu_info->frm_type == dp_tx_frm_me) {
+				prep_desc_fail++;
 				dp_tx_me_free_buf(pdev,
 					(void *)(msdu_info->u.sg_info
 						.curr_seg->frags[0].vaddr));
+				if (prep_desc_fail == msdu_info->num_seg) {
+					/*
+					 * Unmap is needed only if descriptor
+					 * preparation failed for all segments.
+					 */
+					qdf_nbuf_unmap(soc->osdev,
+						       msdu_info->u.sg_info.
+						       curr_seg->nbuf,
+						       QDF_DMA_TO_DEVICE);
+				}
+				/*
+				 * Free the nbuf for the current segment
+				 * and make it point to the next in the list.
+				 * For me, there are as many segments as there
+				 * are no of clients.
+				 */
+				qdf_nbuf_free(msdu_info->u.sg_info
+					      .curr_seg->nbuf);
+				if (msdu_info->u.sg_info.curr_seg->next)
+					msdu_info->u.sg_info.curr_seg =
+						msdu_info->u.sg_info
+						.curr_seg->next;
 				i++;
 				continue;
 			}
@@ -2078,6 +2102,29 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 
 			dp_tx_desc_release(tx_desc, tx_q->desc_pool_id);
 			if (msdu_info->frm_type == dp_tx_frm_me) {
+				hw_enq_fail++;
+				if (hw_enq_fail == msdu_info->num_seg) {
+					/*
+					 * Unmap is needed only if enqueue
+					 * failed for all segments.
+					 */
+					qdf_nbuf_unmap(soc->osdev,
+						       msdu_info->u.sg_info.
+						       curr_seg->nbuf,
+						       QDF_DMA_TO_DEVICE);
+				}
+				/*
+				 * Free the nbuf for the current segment
+				 * and make it point to the next in the list.
+				 * For me, there are as many segments as there
+				 * are no of clients.
+				 */
+				qdf_nbuf_free(msdu_info->u.sg_info
+					      .curr_seg->nbuf);
+				if (msdu_info->u.sg_info.curr_seg->next)
+					msdu_info->u.sg_info.curr_seg =
+						msdu_info->u.sg_info
+						.curr_seg->next;
 				i++;
 				continue;
 			}