Explorar o código

qcacmn: Add frag dma unmap handling for SG packets

DMA unmap for scatter gather packets is done using
only frag0 dma address and the entire packet length
which will lead to incorrect behaviors. Add handling
to do dma unmap for all the fragments of SG packets.

Change-Id: I614553d9f96c573f0095c9be38706fd4ac3223ab
CRs-Fixed: 3112424
Yeshwanth Sriram Guntuka %!s(int64=3) %!d(string=hai) anos
pai
achega
8e11d1a8fb
Modificáronse 2 ficheiros con 107 adicións e 14 borrados
  1. 77 13
      dp/wifi3.0/dp_tx.c
  2. 30 1
      hal/wifi3.0/hal_tx.h

+ 77 - 13
dp/wifi3.0/dp_tx.c

@@ -2119,6 +2119,31 @@ void dp_tx_comp_free_buf(struct dp_soc *soc, struct dp_tx_desc_s *desc)
 			qdf_nbuf_free(nbuf);
 			return;
 		}
+
+		if (qdf_unlikely(desc->frm_type == dp_tx_frm_sg)) {
+			void *msdu_ext_desc = desc->msdu_ext_desc->vaddr;
+			qdf_dma_addr_t iova;
+			uint32_t frag_len;
+			uint32_t i;
+
+			qdf_nbuf_unmap_nbytes_single(soc->osdev, nbuf,
+						     QDF_DMA_TO_DEVICE,
+						     qdf_nbuf_headlen(nbuf));
+
+			for (i = 1; i < DP_TX_MAX_NUM_FRAGS; i++) {
+				hal_tx_ext_desc_get_frag_info(msdu_ext_desc, i,
+							      &iova,
+							      &frag_len);
+				if (!iova || !frag_len)
+					break;
+
+				qdf_mem_unmap_page(soc->osdev, iova, frag_len,
+						   QDF_DMA_TO_DEVICE);
+			}
+
+			qdf_nbuf_free(nbuf);
+			return;
+		}
 	}
 	/* If it's ME frame, dont unmap the cloned nbuf's */
 	if ((desc->flags & DP_TX_DESC_FLAG_ME) && qdf_nbuf_is_cloned(nbuf))
@@ -2133,6 +2158,32 @@ nbuf_free:
 	qdf_nbuf_free(nbuf);
 }
 
+/**
+ * dp_tx_sg_unmap_buf() - Unmap scatter gather fragments
+ * @soc: DP soc handle
+ * @nbuf: skb
+ * @msdu_info: MSDU info
+ *
+ * Return: None
+ */
+static inline void
+dp_tx_sg_unmap_buf(struct dp_soc *soc, qdf_nbuf_t nbuf,
+		   struct dp_tx_msdu_info_s *msdu_info)
+{
+	uint32_t cur_idx;
+	struct dp_tx_seg_info_s *seg = msdu_info->u.sg_info.curr_seg;
+
+	qdf_nbuf_unmap_nbytes_single(soc->osdev, nbuf, QDF_DMA_TO_DEVICE,
+				     qdf_nbuf_headlen(nbuf));
+
+	for (cur_idx = 1; cur_idx < seg->frag_cnt; cur_idx++)
+		qdf_mem_unmap_page(soc->osdev, (qdf_dma_addr_t)
+				   (seg->frags[cur_idx].paddr_lo | ((uint64_t)
+				    seg->frags[cur_idx].paddr_hi) << 32),
+				   seg->frags[cur_idx].len,
+				   QDF_DMA_TO_DEVICE);
+}
+
 /**
  * dp_tx_send_msdu_multiple() - Enqueue multiple MSDUs
  * @vdev: DP vdev handle
@@ -2233,6 +2284,9 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 				}
 			}
 
+			if (msdu_info->frm_type == dp_tx_frm_sg)
+				dp_tx_sg_unmap_buf(soc, nbuf, msdu_info);
+
 			goto done;
 		}
 
@@ -2287,8 +2341,8 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 						     NULL, msdu_info);
 
 		if (status != QDF_STATUS_SUCCESS) {
-			dp_info("Tx_hw_enqueue Fail tx_desc %pK queue %d",
-				tx_desc, tx_q->ring_id);
+			dp_info_rl("Tx_hw_enqueue Fail tx_desc %pK queue %d",
+				   tx_desc, tx_q->ring_id);
 
 			dp_tx_get_tid(vdev, nbuf, msdu_info);
 			tid_stats = &pdev->stats.tid_stats.
@@ -2345,6 +2399,9 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 				continue;
 			}
 
+			if (msdu_info->frm_type == dp_tx_frm_sg)
+				dp_tx_sg_unmap_buf(soc, nbuf, msdu_info);
+
 			dp_tx_desc_release(tx_desc, tx_q->desc_pool_id);
 			goto done;
 		}
@@ -2406,7 +2463,6 @@ static qdf_nbuf_t dp_tx_prepare_sg(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 					   qdf_nbuf_headlen(nbuf))) {
 		dp_tx_err("dma map error");
 		DP_STATS_INC(vdev, tx_i.sg.dma_map_error, 1);
-
 		qdf_nbuf_free(nbuf);
 		return NULL;
 	}
@@ -2418,8 +2474,10 @@ static qdf_nbuf_t dp_tx_prepare_sg(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 	seg_info->frags[0].vaddr = (void *) nbuf;
 
 	for (cur_frag = 0; cur_frag < nr_frags; cur_frag++) {
-		if (QDF_STATUS_E_FAILURE == qdf_nbuf_frag_map(vdev->osdev,
-					nbuf, 0, QDF_DMA_TO_DEVICE, cur_frag)) {
+		if (QDF_STATUS_SUCCESS != qdf_nbuf_frag_map(vdev->osdev,
+							    nbuf, 0,
+							    QDF_DMA_TO_DEVICE,
+							    cur_frag)) {
 			dp_tx_err("frag dma map error");
 			DP_STATS_INC(vdev, tx_i.sg.dma_map_error, 1);
 			goto map_err;
@@ -3168,18 +3226,24 @@ qdf_nbuf_t dp_tx_send(struct cdp_soc_t *soc_hdl, uint8_t vdev_id,
 
 	/* SG */
 	if (qdf_unlikely(qdf_nbuf_is_nonlinear(nbuf))) {
-		struct dp_tx_seg_info_s seg_info = {0};
+		if (qdf_nbuf_get_nr_frags(nbuf) > DP_TX_MAX_NUM_FRAGS - 1) {
+			if (qdf_unlikely(qdf_nbuf_linearize(nbuf)))
+				return nbuf;
+		} else {
+			struct dp_tx_seg_info_s seg_info = {0};
 
-		nbuf = dp_tx_prepare_sg(vdev, nbuf, &seg_info, &msdu_info);
-		if (!nbuf)
-			return NULL;
+			nbuf = dp_tx_prepare_sg(vdev, nbuf, &seg_info,
+						&msdu_info);
+			if (!nbuf)
+				return NULL;
 
-		dp_verbose_debug("non-TSO SG frame %pK", vdev);
+			dp_verbose_debug("non-TSO SG frame %pK", vdev);
 
-		DP_STATS_INC_PKT(vdev, tx_i.sg.sg_pkt, 1,
-				qdf_nbuf_len(nbuf));
+			DP_STATS_INC_PKT(vdev, tx_i.sg.sg_pkt, 1,
+					 qdf_nbuf_len(nbuf));
 
-		goto send_multiple;
+			goto send_multiple;
+		}
 	}
 
 	if (qdf_unlikely(!dp_tx_mcast_enhance(vdev, nbuf)))

+ 30 - 1
hal/wifi3.0/hal_tx.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -67,6 +67,9 @@ do {                                            \
 #define HAL_TX_DESC_GET(desc, block, field) \
 	HAL_TX_MS(block, field, HAL_SET_FLD(desc, block, field))
 
+#define HAL_TX_DESC_OFFSET_GET(desc, block, field, offset) \
+	HAL_TX_MS(block, field, HAL_SET_FLD_OFFSET(desc, block, field, offset))
+
 #define HAL_TX_DESC_SUBBLOCK_GET(desc, block, sub, field) \
 	HAL_TX_MS(sub, field, HAL_SET_FLD(desc, block, sub))
 
@@ -430,6 +433,32 @@ static inline void hal_tx_ext_desc_set_buffer(void *desc,
 		((HAL_TX_SM(HAL_TX_MSDU_EXTENSION, BUF0_LEN, length)));
 }
 
+/**
+ * hal_tx_ext_desc_get_frag_info() - Get the frag_num'th frag iova and len
+ * @desc: Handle to Tx MSDU Extension Descriptor
+ * @frag_num: fragment number (value can be 0 to 5)
+ * @iova: fragment dma address
+ * @len: fragement Length
+ *
+ * Return: None
+ */
+static inline void hal_tx_ext_desc_get_frag_info(void *desc, uint8_t frag_num,
+						 qdf_dma_addr_t *iova,
+						 uint32_t *len)
+{
+	uint64_t iova_hi;
+
+	*iova = HAL_TX_DESC_OFFSET_GET(desc, HAL_TX_MSDU_EXTENSION,
+				       BUF0_PTR_31_0, (frag_num << 3));
+
+	iova_hi = HAL_TX_DESC_OFFSET_GET(desc, HAL_TX_MSDU_EXTENSION,
+					 BUF0_PTR_39_32, (frag_num << 3));
+	*iova |= (iova_hi << 32);
+
+	*len = HAL_TX_DESC_OFFSET_GET(desc, HAL_TX_MSDU_EXTENSION, BUF0_LEN,
+				      (frag_num << 3));
+}
+
 /**
  * hal_tx_ext_desc_set_buffer0_param() - Set Buffer 0 Pointer and Length
  * @desc: Handle to Tx MSDU Extension Descriptor