]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
crypto: talitos/hash - fix SEC2 64k - 1 ahash request limitation
authorPaul Louvel <paul.louvel@bootlin.com>
Thu, 7 May 2026 14:41:57 +0000 (16:41 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 15 May 2026 10:08:48 +0000 (18:08 +0800)
The problem described in commit 655ef638a2bc ("crypto: talitos - fix
SEC1 32k ahash request limitation") also apply for the SEC2 hardware,
but with a limitation of 64k - 1 bytes.

Split ahash_done() into SEC1 and SEC2 paths: SEC1 continues to free the
whole descriptor list at once, while SEC2 now iterates through
descriptors one by one, submitting the next only after the previous
completes, which is required since SEC2 cannot chain descriptors in
hardware.

Cc: stable@vger.kernel.org
Fixes: c662b043cdca ("crypto: af_alg/hash: Support MSG_SPLICE_PAGES")
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/talitos.c

index 551b41e813f01f5740998112fd317915b86c05b8..2d69ee608665889727f5116109c56bc0c28e2821 100644 (file)
@@ -1820,16 +1820,46 @@ static void ahash_done(struct device *dev,
        struct talitos_edesc *edesc =
                 container_of(desc, struct talitos_edesc, desc);
        struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       bool is_sec1 = has_ftr_sec1(dev_get_drvdata(dev));
+       struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+       struct talitos_edesc *next;
 
-       if (!req_ctx->last_request && req_ctx->to_hash_later) {
-               /* Position any partial block for next update/final/finup */
-               req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
-               req_ctx->nbuf = req_ctx->to_hash_later;
-       }
+       if (is_sec1) {
+               if (!req_ctx->last_request && req_ctx->to_hash_later) {
+                       /* Position any partial block for next update/final/finup */
+                       req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+                       req_ctx->nbuf = req_ctx->to_hash_later;
+               }
+
+               free_edesc_list_from(areq, edesc);
+               ahash_request_complete(areq, err);
+       } else {
+               next = edesc->next_desc;
 
-       free_edesc_list_from(areq, edesc);
+               common_nonsnoop_hash_unmap(dev, edesc, areq);
+               kfree(edesc);
 
-       ahash_request_complete(areq, err);
+               if (err)
+                       goto out;
+
+               if (next) {
+                       err = talitos_submit(dev, ctx->ch, &next->desc,
+                                            ahash_done, areq);
+                       if (err != -EINPROGRESS)
+                               goto out;
+                       return;
+               }
+out:
+               if (!req_ctx->last_request && req_ctx->to_hash_later) {
+                       /* Position any partial block for next update/final/finup */
+                       req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+                       req_ctx->nbuf = req_ctx->to_hash_later;
+               }
+               if (err && next)
+                       free_edesc_list_from(areq, next);
+               ahash_request_complete(areq, err);
+       }
 }
 
 /*
@@ -1940,7 +1970,8 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes,
        struct talitos_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
        struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
        struct talitos_edesc *first = NULL, *prev_edesc = NULL, *edesc;
-       size_t desc_max = is_sec1 ? TALITOS1_MAX_DATA_LEN : SIZE_MAX;
+       size_t desc_max = is_sec1 ? TALITOS1_MAX_DATA_LEN :
+                                   TALITOS2_MAX_DATA_LEN;
        struct scatterlist tmp[2];
        size_t to_hash_this_desc;
        struct scatterlist *src;