From fd8d282a7571c63cbe3a1dcc2604fb8b2e9b3fed Mon Sep 17 00:00:00 2001 From: Chaoli Zhou Date: Wed, 25 Sep 2019 15:32:04 +0800 Subject: [PATCH] qcacld-3.0: Fix WDI 1.0 MCC TX SMMU fault Merge from 2517936 & 2490501. 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. After doing DMA map, an offset of frag_header and ipa_header is added to the iova and skb->cb is updated with the new iova. After TX completion, skb DMA unmap is done but with the iova of the above offset included, which leads to unmapped iova error. Fix is to recalculate the iova and update skb->cb with new iova, which has frag_header and ipa_header length removed. Change-Id: Ib0112d6a3de6dc9af43e5c48a49085c7d4f41a9b CRs-Fixed: 2534845 --- components/ipa/core/src/wlan_ipa_core.c | 77 ++++++++++++++++++++-- core/dp/txrx/ol_tx_desc.c | 8 ++- core/dp/txrx/ol_txrx_legacy_flow_control.c | 10 +-- 3 files changed, 82 insertions(+), 13 deletions(-) diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c index 79f49cc0b89c..73bc5e514572 100644 --- a/components/ipa/core/src/wlan_ipa_core.c +++ b/components/ipa/core/src/wlan_ipa_core.c @@ -235,8 +235,19 @@ 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; + struct wlan_objmgr_psoc *psoc; + qdf_device_t osdev; qdf_nbuf_t skb; struct wlan_ipa_tx_desc *tx_desc; + qdf_dma_addr_t paddr; + QDF_STATUS status; + + if (!ipa_ctx) + return; + pdev = ipa_ctx->pdev; + psoc = wlan_pdev_get_psoc(pdev); + osdev = wlan_psoc_get_qdf_dev(psoc); qdf_spin_lock_bh(&iface_context->interface_lock); /* @@ -253,6 +264,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); @@ -261,15 +280,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 */ @@ -284,6 +321,14 @@ static void wlan_ipa_send_pkt_to_tl( } else { ipa_ctx->stats.num_tx_desc_error++; qdf_spin_unlock_bh(&ipa_ctx->q_lock); + + if (qdf_mem_smmu_s1_enabled(osdev)) { + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) + qdf_nbuf_mapped_paddr_set(skb, paddr); + + qdf_nbuf_unmap(osdev, skb, QDF_DMA_TO_DEVICE); + } + qdf_ipa_free_skb(ipa_tx_desc); wlan_ipa_wdi_rm_try_release(ipa_ctx); return; @@ -1386,12 +1431,34 @@ static void wlan_ipa_nbuf_cb(qdf_nbuf_t skb) qdf_ipa_rx_data_t *ipa_tx_desc; struct wlan_ipa_tx_desc *tx_desc; uint16_t id; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + qdf_device_t osdev; if (!qdf_nbuf_ipa_owned_get(skb)) { dev_kfree_skb_any(skb); return; } + if (!ipa_ctx) + return; + pdev = ipa_ctx->pdev; + psoc = wlan_pdev_get_psoc(pdev); + osdev = wlan_psoc_get_qdf_dev(psoc); + + if (osdev && qdf_mem_smmu_s1_enabled(osdev)) { + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + qdf_dma_addr_t paddr = QDF_NBUF_CB_PADDR(skb); + + qdf_nbuf_mapped_paddr_set(skb, + paddr - + WLAN_IPA_WLAN_FRAG_HEADER - + WLAN_IPA_WLAN_IPA_HEADER); + } + + qdf_nbuf_unmap(osdev, skb, QDF_DMA_TO_DEVICE); + } + /* Get Tx desc pointer from SKB CB */ id = QDF_NBUF_CB_TX_IPA_PRIV(skb); tx_desc = &ipa_ctx->tx_desc_pool[id]; diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 040c0203b85e..f56d917c152a 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/core/dp/txrx/ol_tx_desc.c @@ -886,9 +886,11 @@ 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); + } /* 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 7e8ce3fc40a2..4900de373a6f 100644 --- a/core/dp/txrx/ol_txrx_legacy_flow_control.c +++ b/core/dp/txrx/ol_txrx_legacy_flow_control.c @@ -129,11 +129,11 @@ 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); } qdf_nbuf_tx_free(vdev->ll_pause.txq.head, QDF_NBUF_PKT_ERROR);