From 46d673033b7f6974d0bf5696ff8365fd412cd646 Mon Sep 17 00:00:00 2001
From: Aviana Cruz <gwencroft@proton.me>
Date: Mon, 20 Jun 2022 21:55:45 +0800
Subject: [PATCH] crypto: eip93 - use AES fallback for small requests

For data blocks smaller than 1024, software crypto is faster.

Signed-off-by: Aviana Cruz <gwencroft@proton.me>
---

--- a/drivers/crypto/inside-secure/eip93/Kconfig
+++ b/drivers/crypto/inside-secure/eip93/Kconfig
@@ -18,3 +18,19 @@ config CRYPTO_DEV_EIP93
 	  CTR crypto. Also provide DES and 3DES ECB and CBC.
 
 	  Also provide AEAD authenc(hmac(x), cipher(y)) for supported algo.
+
+config CRYPTO_DEV_EIP93_GENERIC_SW_MAX_LEN
+	int "Max skcipher software fallback length"
+	depends on CRYPTO_DEV_EIP93
+	default 256
+	help
+	  Max length of crypt request which
+	  will fallback to software crypt of skcipher *except* AES-128.
+
+config CRYPTO_DEV_EIP93_AES_128_SW_MAX_LEN
+	int "Max AES-128 skcipher software fallback length"
+	depends on CRYPTO_DEV_EIP93
+	default 512
+	help
+	  Max length of crypt request which
+	  will fallback to software crypt of AES-128 skcipher.
--- a/drivers/crypto/inside-secure/eip93/eip93-cipher.c
+++ b/drivers/crypto/inside-secure/eip93/eip93-cipher.c
@@ -30,6 +30,13 @@ void eip93_skcipher_handle_result(struct
 	skcipher_request_complete(req, err);
 }
 
+static inline bool eip93_skcipher_is_fallback(const struct crypto_tfm *tfm,
+					      u32 flags)
+{
+	return (tfm->__crt_alg->cra_flags & CRYPTO_ALG_NEED_FALLBACK) &&
+		!IS_RFC3686(flags);
+}
+
 static int eip93_skcipher_send_req(struct crypto_async_request *async)
 {
 	struct skcipher_request *req = skcipher_request_cast(async);
@@ -52,12 +59,21 @@ static int eip93_skcipher_cra_init(struc
 	struct eip93_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct eip93_alg_template *tmpl = container_of(tfm->__crt_alg,
 				struct eip93_alg_template, alg.skcipher.base);
-
-	crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
-				    sizeof(struct eip93_cipher_reqctx));
+	bool fallback = eip93_skcipher_is_fallback(tfm, tmpl->flags);
 
 	memset(ctx, 0, sizeof(*ctx));
 
+	if (fallback) {
+		ctx->fallback = crypto_alloc_skcipher(
+			crypto_tfm_alg_name(tfm), 0, CRYPTO_ALG_NEED_FALLBACK);
+		if (IS_ERR(ctx->fallback))
+			return PTR_ERR(ctx->fallback);
+	}
+
+	crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
+				    sizeof(struct eip93_cipher_reqctx) + (fallback ?
+				    crypto_skcipher_reqsize(ctx->fallback) : 0));
+
 	ctx->eip93 = tmpl->eip93;
 	ctx->type = tmpl->type;
 
@@ -75,6 +91,8 @@ static void eip93_skcipher_cra_exit(stru
 	dma_unmap_single(ctx->eip93->dev, ctx->sa_record_base,
 			 sizeof(*ctx->sa_record), DMA_TO_DEVICE);
 	kfree(ctx->sa_record);
+
+	crypto_free_skcipher(ctx->fallback);
 }
 
 static int eip93_skcipher_setkey(struct crypto_skcipher *ctfm, const u8 *key,
@@ -117,6 +135,14 @@ static int eip93_skcipher_setkey(struct
 
 	if (flags & EIP93_ALG_AES) {
 		struct crypto_aes_ctx aes;
+		bool fallback = eip93_skcipher_is_fallback(tfm, flags);
+
+		if (fallback && !IS_RFC3686(flags)) {
+			ret = crypto_skcipher_setkey(ctx->fallback, key,
+						     keylen);
+			if (ret)
+				return ret;
+		}
 
 		ctx->blksize = AES_BLOCK_SIZE;
 		ret = aes_expandkey(&aes, key, keylen);
@@ -133,12 +159,13 @@ static int eip93_skcipher_setkey(struct
 	return 0;
 }
 
-static int eip93_skcipher_crypt(struct skcipher_request *req)
+static int eip93_skcipher_crypt(struct skcipher_request *req, bool encrypt)
 {
 	struct eip93_cipher_reqctx *rctx = skcipher_request_ctx(req);
 	struct crypto_async_request *async = &req->base;
 	struct eip93_crypto_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+	bool fallback = eip93_skcipher_is_fallback(req->base.tfm, rctx->flags);
 	int ret;
 
 	if (!req->cryptlen)
@@ -153,6 +180,21 @@ static int eip93_skcipher_crypt(struct s
 				crypto_skcipher_blocksize(skcipher)))
 			return -EINVAL;
 
+	if (fallback &&
+	    req->cryptlen <= (AES_KEYSIZE_128 ?
+			      CONFIG_CRYPTO_DEV_EIP93_AES_128_SW_MAX_LEN :
+			      CONFIG_CRYPTO_DEV_EIP93_GENERIC_SW_MAX_LEN)) {
+		skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+		skcipher_request_set_callback(&rctx->fallback_req,
+					      req->base.flags,
+					      req->base.complete,
+					      req->base.data);
+		skcipher_request_set_crypt(&rctx->fallback_req, req->src,
+					   req->dst, req->cryptlen, req->iv);
+		return encrypt ? crypto_skcipher_encrypt(&rctx->fallback_req) :
+				 crypto_skcipher_decrypt(&rctx->fallback_req);
+	}
+
 	ctx->sa_record_base = dma_map_single(ctx->eip93->dev, ctx->sa_record,
 					     sizeof(*ctx->sa_record), DMA_TO_DEVICE);
 	ret = dma_mapping_error(ctx->eip93->dev, ctx->sa_record_base);
@@ -181,7 +223,7 @@ static int eip93_skcipher_encrypt(struct
 	rctx->flags = tmpl->flags;
 	rctx->flags |= EIP93_ENCRYPT;
 
-	return eip93_skcipher_crypt(req);
+	return eip93_skcipher_crypt(req, true);
 }
 
 static int eip93_skcipher_decrypt(struct skcipher_request *req)
@@ -196,7 +238,7 @@ static int eip93_skcipher_decrypt(struct
 	rctx->flags = tmpl->flags;
 	rctx->flags |= EIP93_DECRYPT;
 
-	return eip93_skcipher_crypt(req);
+	return eip93_skcipher_crypt(req, false);
 }
 
 /* Available algorithms in this module */
--- a/drivers/crypto/inside-secure/eip93/eip93-cipher.h
+++ b/drivers/crypto/inside-secure/eip93/eip93-cipher.h
@@ -22,6 +22,7 @@ struct eip93_crypto_ctx {
 	unsigned int			assoclen;
 	bool				set_assoc;
 	enum eip93_alg_type		type;
+	struct crypto_skcipher		*fallback;
 };
 
 struct eip93_cipher_reqctx {
@@ -42,6 +43,7 @@ struct eip93_cipher_reqctx {
 	int				dst_nents;
 	struct sa_state			*sa_state_ctr;
 	dma_addr_t			sa_state_ctr_base;
+	struct skcipher_request		fallback_req;
 };
 
 int check_valid_request(struct eip93_cipher_reqctx *rctx);
