]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Jul 2019 07:12:25 +0000 (09:12 +0200)
[ Upstream commit dcd9c76e5a183af4f793beb5141efcd260b8d09f ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamalg_qi.c
drivers/crypto/caam/caamalg_qi2.c
drivers/crypto/caam/qi.c

index 579578498debba63f5bbe9efa54b872fc1da1c18..00e72847ed9ec0e82637d120492f00949fd5238b 100644 (file)
@@ -1072,6 +1072,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 c61921d32489a53386d4eafaf258150bff1bd368..96d1a9647b01f82274fdcad7ab441aa84d734a6d 100644 (file)
@@ -1068,7 +1068,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 0a72c96708c48304793d62d4fa4e928d31c79f8b..faf238db153c69e159410e4b7974cda3e7d93d60 100644 (file)
@@ -525,6 +525,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));
@@ -536,6 +544,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 7cb8b1755e57b12acc81abf986ef60d3b1618d1b..976aa9b3b264dcf28dfdb24015275dd8fb78faaf 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,