From a244137e6699af419d3e1b0094acb8bbf6bc2858 Mon Sep 17 00:00:00 2001 From: jiad Date: Tue, 25 Sep 2018 11:02:09 +0800 Subject: [PATCH] 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 --- components/ipa/core/src/wlan_ipa_core.c | 41 +++++++++++++++++++--- core/dp/txrx/ol_tx_desc.c | 11 ++++-- core/dp/txrx/ol_txrx_legacy_flow_control.c | 14 +++++--- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c index cc39fe7994ad..27f1152bde80 100644 --- a/components/ipa/core/src/wlan_ipa_core.c +++ b/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 */ diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 932276246a24..b517702be0db 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/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); diff --git a/core/dp/txrx/ol_txrx_legacy_flow_control.c b/core/dp/txrx/ol_txrx_legacy_flow_control.c index bcf28c28310e..2b72a5ad4c83 100644 --- a/core/dp/txrx/ol_txrx_legacy_flow_control.c +++ b/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);