Explorar el Código

qcacld-3.0: Fix WDI 1.0 MCC TX SMMU fault

SMMU fault is observed for WDI 1.0 MCC TX when SMMU is enabled.
Issue is that dma_addr passed from IPA driver is iova of IPA
domain. WLAN driver directly uses the iova to do transmission.
Since iova is not mapped in WLAN domain, SMMU fault occurs.

Fix is to map skb to WLAN domain for TX when SMMU is enabled.

Change-Id: I4c029a1e4dfff149e2784f5b95fe1f3cf3e3719e
CRs-Fixed: 2318537
jiad hace 6 años
padre
commit
a244137e66

+ 36 - 5
components/ipa/core/src/wlan_ipa_core.c

@@ -205,8 +205,13 @@ static void wlan_ipa_send_pkt_to_tl(
 		qdf_ipa_rx_data_t *ipa_tx_desc)
 {
 	struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
+	struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+	qdf_device_t osdev = wlan_psoc_get_qdf_dev(psoc);
 	qdf_nbuf_t skb;
 	struct wlan_ipa_tx_desc *tx_desc;
+	qdf_dma_addr_t paddr;
+	QDF_STATUS status;
 
 	qdf_spin_lock_bh(&iface_context->interface_lock);
 	/*
@@ -223,6 +228,14 @@ static void wlan_ipa_send_pkt_to_tl(
 			return;
 		}
 	}
+
+	if (!osdev) {
+		ipa_free_skb(ipa_tx_desc);
+		iface_context->stats.num_tx_drop++;
+		qdf_spin_unlock_bh(&iface_context->interface_lock);
+		wlan_ipa_wdi_rm_try_release(ipa_ctx);
+		return;
+	}
 	qdf_spin_unlock_bh(&iface_context->interface_lock);
 
 	skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
@@ -231,15 +244,33 @@ static void wlan_ipa_send_pkt_to_tl(
 
 	/* Store IPA Tx buffer ownership into SKB CB */
 	qdf_nbuf_ipa_owned_set(skb);
+
+	if (qdf_mem_smmu_s1_enabled(osdev)) {
+		status = qdf_nbuf_map(osdev, skb, QDF_DMA_TO_DEVICE);
+		if (QDF_IS_STATUS_SUCCESS(status)) {
+			paddr = qdf_nbuf_get_frag_paddr(skb, 0);
+		} else {
+			ipa_free_skb(ipa_tx_desc);
+			qdf_spin_lock_bh(&iface_context->interface_lock);
+			iface_context->stats.num_tx_drop++;
+			qdf_spin_unlock_bh(&iface_context->interface_lock);
+			wlan_ipa_wdi_rm_try_release(ipa_ctx);
+			return;
+		}
+	} else {
+		paddr = QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc);
+	}
+
 	if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
 		qdf_nbuf_mapped_paddr_set(skb,
-					  QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
-					  + WLAN_IPA_WLAN_FRAG_HEADER
-					  + WLAN_IPA_WLAN_IPA_HEADER);
+					  paddr +
+					  WLAN_IPA_WLAN_FRAG_HEADER +
+					  WLAN_IPA_WLAN_IPA_HEADER);
 		QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
 			WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER;
-	} else
-		qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
+	} else {
+		qdf_nbuf_mapped_paddr_set(skb, paddr);
+	}
 
 	qdf_spin_lock_bh(&ipa_ctx->q_lock);
 	/* get free Tx desc and assign ipa_tx_desc pointer */

+ 8 - 3
core/dp/txrx/ol_tx_desc.c

@@ -797,9 +797,14 @@ void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev,
 		 * DMA mapped address. In such case, there's no need for WLAN
 		 * driver to DMA unmap the skb.
 		 */
-		if ((qdf_nbuf_get_users(msdu) <= 1) &&
-				!qdf_nbuf_ipa_owned_get(msdu))
-			qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_TO_DEVICE);
+		if (qdf_nbuf_get_users(msdu) <= 1) {
+			if (!qdf_nbuf_ipa_owned_get(msdu))
+				qdf_nbuf_unmap(pdev->osdev, msdu,
+					       QDF_DMA_TO_DEVICE);
+			else if (qdf_mem_smmu_s1_enabled(pdev->osdev))
+				qdf_nbuf_unmap(pdev->osdev, msdu,
+					       QDF_DMA_TO_DEVICE);
+		}
 
 		/* free the tx desc */
 		ol_tx_desc_free(pdev, tx_desc);

+ 9 - 5
core/dp/txrx/ol_txrx_legacy_flow_control.c

@@ -129,11 +129,15 @@ void ol_txrx_vdev_flush(struct cdp_vdev *pvdev)
 		qdf_nbuf_t next =
 			qdf_nbuf_next(vdev->ll_pause.txq.head);
 		qdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL);
-		if (QDF_NBUF_CB_PADDR(vdev->ll_pause.txq.head) &&
-		    !qdf_nbuf_ipa_owned_get(vdev->ll_pause.txq.head)) {
-			qdf_nbuf_unmap(vdev->pdev->osdev,
-				       vdev->ll_pause.txq.head,
-				       QDF_DMA_TO_DEVICE);
+		if (QDF_NBUF_CB_PADDR(vdev->ll_pause.txq.head)) {
+			if (!qdf_nbuf_ipa_owned_get(vdev->ll_pause.txq.head))
+				qdf_nbuf_unmap(vdev->pdev->osdev,
+					       vdev->ll_pause.txq.head,
+					       QDF_DMA_TO_DEVICE);
+			else if (qdf_mem_smmu_s1_enabled(vdev->pdev->osdev))
+				qdf_nbuf_unmap(vdev->pdev->osdev,
+					       vdev->ll_pause.txq.head,
+					       QDF_DMA_TO_DEVICE);
 		}
 		qdf_nbuf_tx_free(vdev->ll_pause.txq.head,
 				 QDF_NBUF_PKT_ERROR);