crypto: caam - avoid S/G table fetching for AEAD zero-length output
authorHoria Geantă <horia.geanta@nxp.com>
Fri, 3 May 2019 14:17:37 +0000 (17:17 +0300)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 23 May 2019 06:01:03 +0000 (14:01 +0800)
When enabling IOMMU support, the following issue becomes visible
in the AEAD zero-length case.

Even though the output sequence length is set to zero, the crypto engine
tries to prefetch 4 S/G table entries (since SGF bit is set
in SEQ OUT PTR command - which is either generated in SW in case of
caam/jr or in HW in case of caam/qi, caam/qi2).
The DMA read operation will trigger an IOMMU fault since the address in
the SEQ OUT PTR is "dummy" (set to zero / not obtained via DMA API
mapping).

1. In case of caam/jr, avoid the IOMMU fault by clearing the SGF bit
in SEQ OUT PTR command.

2. In case of caam/qi - setting address, bpid, length to zero for output
entry in the compound frame has a special meaning (cf. CAAM RM):
"Output frame = Unspecified, Input address = Y. A unspecified frame is
indicated by an unused SGT entry (an entry in which the Address, Length,
and BPID fields are all zero). SEC obtains output buffers from BMan as
prescribed by the preheader."

Since no output buffers are needed, modify the preheader by setting
(ABS = 1, ADDBUF = 0):
-"ABS = 1 means obtain the number of buffers in ADDBUF (0 or 1) from
the pool POOL ID"
-ADDBUF: "If ABS is set, ADD BUF specifies whether to allocate
a buffer or not"

3. In case of caam/qi2, since engine:
-does not support FLE[FMT]=2'b11 ("unused" entry) mentioned in DPAA2 RM
-requires output entry to be present, even if not used
the solution chosen is to leave output frame list entry zeroized.

Fixes: 763069ba49d3 ("crypto: caam - handle zero-length AEAD output")
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamalg_qi.c
drivers/crypto/caam/caamalg_qi2.c
drivers/crypto/caam/qi.c

index c0ece44f303b6cac772b831318731dc4859f6636..df416e6c14684abc3bd7e463faaf10830b58bfcd 100644 (file)
@@ -1106,6 +1106,7 @@ static void init_aead_job(struct aead_request *req,
        if (unlikely(req->src != req->dst)) {
                if (!edesc->mapped_dst_nents) {
                        dst_dma = 0;
+                       out_options = 0;
                } else if (edesc->mapped_dst_nents == 1) {
                        dst_dma = sg_dma_address(req->dst);
                        out_options = 0;
index d290d6b41825e54d1ff1d9f316d3a1c2e35986bd..116cbc81fa8d92757c28d93880bc39813eeda590 100644 (file)
@@ -1109,7 +1109,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
                        dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma +
                                             (1 + !!ivsize) * sizeof(*sg_table),
                                             out_len, 0);
-       } else if (mapped_dst_nents == 1) {
+       } else if (mapped_dst_nents <= 1) {
                dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), out_len,
                                 0);
        } else {
index 2b2980a8a9b90ed33a887d6112266df53c41319f..b949944c8e55461baacf37643373d4dbb4f0ceca 100644 (file)
@@ -559,6 +559,14 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
                        dpaa2_fl_set_addr(out_fle, qm_sg_dma +
                                          (1 + !!ivsize) * sizeof(*sg_table));
                }
+       } else if (!mapped_dst_nents) {
+               /*
+                * crypto engine requires the output entry to be present when
+                * "frame list" FD is used.
+                * Since engine does not support FMT=2'b11 (unused entry type),
+                * leaving out_fle zeroized is the best option.
+                */
+               goto skip_out_fle;
        } else if (mapped_dst_nents == 1) {
                dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
                dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
@@ -570,6 +578,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
 
        dpaa2_fl_set_len(out_fle, out_len);
 
+skip_out_fle:
        return edesc;
 }
 
index 9f08f84cca596e780c444f687c1a89735cfcf030..2d9b0485141fbfc74f13c51912ac402fe4fe8aba 100644 (file)
@@ -18,6 +18,7 @@
 #include "desc_constr.h"
 
 #define PREHDR_RSLS_SHIFT      31
+#define PREHDR_ABS             BIT(25)
 
 /*
  * Use a reasonable backlog of frames (per CPU) as congestion threshold,
@@ -346,6 +347,7 @@ int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc)
         */
        drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) |
                                           num_words);
+       drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS);
        memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc));
        dma_sync_single_for_device(qidev, drv_ctx->context_a,
                                   sizeof(drv_ctx->sh_desc) +
@@ -401,6 +403,7 @@ struct caam_drv_ctx *caam_drv_ctx_init(struct device *qidev,
         */
        drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) |
                                           num_words);
+       drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS);
        memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc));
        size = sizeof(drv_ctx->prehdr) + sizeof(drv_ctx->sh_desc);
        hwdesc = dma_map_single(qidev, drv_ctx->prehdr, size,