From: Gagandeep Singh <[email protected]>

fle_sdd_pre_populate() and fle_sdd_sg_pre_populate() converted the SDD
and SG entry virtual addresses to IOVA with DPAA2_VADDR_TO_IOVA(), which
does not verify that the range is actually mapped in the IOMMU/SMMU. An
unmapped buffer was silently programmed into the hardware descriptor,
leading to an SMMU translation fault at transfer time that is hard to
trace back to the missing mapping.

Use DPAA2_VADDR_TO_IOVA_AND_CHECK() for the SDD, source SG and
destination SG buffers and report the offending address and size when
the translation is missing, so the misconfiguration is caught early and
clearly. Both helpers now return an error code which is propagated to
the caller instead of continuing with an invalid descriptor.

Signed-off-by: Gagandeep Singh <[email protected]>
---
 drivers/dma/dpaa2/dpaa2_qdma.c | 50 ++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 9 deletions(-)

diff --git a/drivers/dma/dpaa2/dpaa2_qdma.c b/drivers/dma/dpaa2/dpaa2_qdma.c
index 45d7a99805..4ad72c5816 100644
--- a/drivers/dma/dpaa2/dpaa2_qdma.c
+++ b/drivers/dma/dpaa2/dpaa2_qdma.c
@@ -180,14 +180,23 @@ dpaa2_qdma_multi_eq(struct qdma_virt_queue *qdma_vq)
        return num_tx;
 }
 
-static void
+static int
 fle_sdd_pre_populate(struct qdma_cntx_fle_sdd *fle_sdd,
        struct dpaa2_qdma_rbp *rbp, uint64_t src, uint64_t dest,
        uint32_t fmt)
 {
        struct qbman_fle *fle = fle_sdd->fle;
        struct qdma_sdd *sdd = fle_sdd->sdd;
-       uint64_t sdd_iova = DPAA2_VADDR_TO_IOVA(sdd);
+       uint64_t sdd_iova, iova_size;
+
+       iova_size = sizeof(struct qdma_sdd) * DPAA2_QDMA_MAX_SDD;
+       sdd_iova = DPAA2_VADDR_TO_IOVA_AND_CHECK(sdd, iova_size);
+       if (sdd_iova == RTE_BAD_IOVA) {
+               DPAA2_QDMA_ERR("No IOMMU map for sdd(%p)(size=%" PRIx64 ")",
+                       sdd, iova_size);
+
+               return -ENOMEM;
+       }
 
        /* first frame list to source descriptor */
        DPAA2_SET_FLE_ADDR(&fle[DPAA2_QDMA_SDD_FLE], sdd_iova);
@@ -256,6 +265,8 @@ fle_sdd_pre_populate(struct qdma_cntx_fle_sdd *fle_sdd,
 
        /* Final bit: 1, for last frame list */
        DPAA2_SET_FLE_FIN(&fle[DPAA2_QDMA_DST_FLE]);
+
+       return 0;
 }
 
 static void
@@ -283,22 +294,39 @@ sg_entry_pre_populate(struct qdma_cntx_sg *sg_cntx)
        }
 }
 
-static void
+static int
 fle_sdd_sg_pre_populate(struct qdma_cntx_sg *sg_cntx,
        struct qdma_virt_queue *qdma_vq)
 {
        struct qdma_sg_entry *src_sge = sg_cntx->sg_src_entry;
        struct qdma_sg_entry *dst_sge = sg_cntx->sg_dst_entry;
-       rte_iova_t src_sge_iova, dst_sge_iova;
+       rte_iova_t src_sge_iova, dst_sge_iova, iova_size;
        struct dpaa2_qdma_rbp *rbp = &qdma_vq->rbp;
 
        memset(sg_cntx, 0, sizeof(struct qdma_cntx_sg));
 
-       src_sge_iova = DPAA2_VADDR_TO_IOVA(src_sge);
-       dst_sge_iova = DPAA2_VADDR_TO_IOVA(dst_sge);
+       iova_size = RTE_DPAAX_QDMA_JOB_SUBMIT_MAX *
+               sizeof(struct qdma_sg_entry);
+
+       src_sge_iova = DPAA2_VADDR_TO_IOVA_AND_CHECK(src_sge, iova_size);
+       if (src_sge_iova == RTE_BAD_IOVA) {
+               DPAA2_QDMA_ERR("No IOMMU map for src_sge(%p)(size=%" PRIx64 ")",
+                       src_sge, iova_size);
+
+               return -ENOMEM;
+       }
+
+       dst_sge_iova = DPAA2_VADDR_TO_IOVA_AND_CHECK(dst_sge, iova_size);
+       if (dst_sge_iova == RTE_BAD_IOVA) {
+               DPAA2_QDMA_ERR("No IOMMU map for dst_sge(%p)(size=%" PRIx64 ")",
+                       dst_sge, iova_size);
+
+               return -ENOMEM;
+       }
 
        sg_entry_pre_populate(sg_cntx);
-       fle_sdd_pre_populate(&sg_cntx->fle_sdd,
+
+       return fle_sdd_pre_populate(&sg_cntx->fle_sdd,
                rbp, src_sge_iova, dst_sge_iova,
                QBMAN_FLE_WORD4_FMT_SGE);
 }
@@ -669,7 +697,9 @@ dpaa2_qdma_copy_sg(void *dev_private,
 
        if (qdma_vq->fle_pre_populate) {
                if (unlikely(!fle[DPAA2_QDMA_SRC_FLE].length)) {
-                       fle_sdd_sg_pre_populate(cntx_sg, qdma_vq);
+                       ret = fle_sdd_sg_pre_populate(cntx_sg, qdma_vq);
+                       if (ret)
+                               return ret;
                        if (!qdma_dev->is_silent && cntx_sg && idx_addr) {
                                for (i = 0; i < nb_src; i++)
                                        cntx_sg->cntx_idx[i] = idx_addr[i];
@@ -871,9 +901,11 @@ dpaa2_qdma_long_copy(struct qdma_virt_queue *qdma_vq,
 
        if (qdma_vq->fle_pre_populate) {
                if (unlikely(!fle[DPAA2_QDMA_SRC_FLE].length)) {
-                       fle_sdd_pre_populate(fle_sdd,
+                       ret = fle_sdd_pre_populate(fle_sdd,
                                &qdma_vq->rbp,
                                0, 0, QBMAN_FLE_WORD4_FMT_SBF);
+                       if (ret)
+                               return ret;
                }
 
                fle_post_populate(fle, src, dst, length);
-- 
2.43.0

Reply via email to