]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto: acomp - Add async nondma fallback
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 15 Mar 2025 10:30:38 +0000 (18:30 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 21 Mar 2025 09:33:39 +0000 (17:33 +0800)
Add support for passing non-DMA virtual addresses to async drivers
by passing them along to the fallback software algorithm.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/acompress.c

index 9da033ded193ee757423fc0ded2569608bfca6b4..d54abc27330f24be4b27b7cd42dea56eb9590ce8 100644 (file)
@@ -152,20 +152,6 @@ struct crypto_acomp *crypto_alloc_acomp_node(const char *alg_name, u32 type,
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_acomp_node);
 
-static bool acomp_request_has_nondma(struct acomp_req *req)
-{
-       struct acomp_req *r2;
-
-       if (acomp_request_isnondma(req))
-               return true;
-
-       list_for_each_entry(r2, &req->base.list, base.list)
-               if (acomp_request_isnondma(r2))
-                       return true;
-
-       return false;
-}
-
 static void acomp_save_req(struct acomp_req *req, crypto_completion_t cplt)
 {
        struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
@@ -234,6 +220,45 @@ static void acomp_virt_to_sg(struct acomp_req *req)
        }
 }
 
+static int acomp_do_nondma(struct acomp_req_chain *state,
+                          struct acomp_req *req)
+{
+       u32 keep = CRYPTO_ACOMP_REQ_SRC_VIRT |
+                  CRYPTO_ACOMP_REQ_SRC_NONDMA |
+                  CRYPTO_ACOMP_REQ_DST_VIRT |
+                  CRYPTO_ACOMP_REQ_DST_NONDMA;
+       ACOMP_REQUEST_ON_STACK(fbreq, crypto_acomp_reqtfm(req));
+       int err;
+
+       acomp_request_set_callback(fbreq, req->base.flags, NULL, NULL);
+       fbreq->base.flags &= ~keep;
+       fbreq->base.flags |= req->base.flags & keep;
+       fbreq->src = req->src;
+       fbreq->dst = req->dst;
+       fbreq->slen = req->slen;
+       fbreq->dlen = req->dlen;
+
+       if (state->op == crypto_acomp_reqtfm(req)->compress)
+               err = crypto_acomp_compress(fbreq);
+       else
+               err = crypto_acomp_decompress(fbreq);
+
+       req->dlen = fbreq->dlen;
+       return err;
+}
+
+static int acomp_do_one_req(struct acomp_req_chain *state,
+                           struct acomp_req *req)
+{
+       state->cur = req;
+
+       if (acomp_request_isnondma(req))
+               return acomp_do_nondma(state, req);
+
+       acomp_virt_to_sg(req);
+       return state->op(req);
+}
+
 static int acomp_reqchain_finish(struct acomp_req_chain *state,
                                 int err, u32 mask)
 {
@@ -252,10 +277,8 @@ static int acomp_reqchain_finish(struct acomp_req_chain *state,
                req->base.flags &= mask;
                req->base.complete = acomp_reqchain_done;
                req->base.data = state;
-               state->cur = req;
 
-               acomp_virt_to_sg(req);
-               err = state->op(req);
+               err = acomp_do_one_req(state, req);
 
                if (err == -EINPROGRESS) {
                        if (!list_empty(&state->head))
@@ -308,27 +331,17 @@ static int acomp_do_req_chain(struct acomp_req *req,
            (!acomp_request_chained(req) && !acomp_request_isvirt(req)))
                return op(req);
 
-       /*
-        * There are no in-kernel users that do this.  If and ever
-        * such users come into being then we could add a fall-back
-        * path.
-        */
-       if (acomp_request_has_nondma(req))
-               return -EINVAL;
-
        if (acomp_is_async(tfm)) {
                acomp_save_req(req, acomp_reqchain_done);
                state = req->base.data;
        }
 
        state->op = op;
-       state->cur = req;
        state->src = NULL;
        INIT_LIST_HEAD(&state->head);
        list_splice_init(&req->base.list, &state->head);
 
-       acomp_virt_to_sg(req);
-       err = op(req);
+       err = acomp_do_one_req(state, req);
        if (err == -EBUSY || err == -EINPROGRESS)
                return -EBUSY;