From c1e75c6c27ea54dec9e31223af49e33aa0d38490 Mon Sep 17 00:00:00 2001
From: Kai Ye <yekai13@huawei.com>
Date: Mon, 13 Dec 2021 18:55:32 +0800
Subject: [PATCH 01/28] uadk/digest - add stream mode for digest sync

Support the sec digest steam mode. Using the session to store
the stream BD state, using the iv_bytes to notify the BD state
from message. So one session only supports one stream.  User
can use the has_next flag to indicate whether there is any
packet to be input.

Signed-off-by: Kai Ye <yekai13@huawei.com>
---
 drv/hisi_sec.c              | 50 ++++++++++++++++++++-----------------
 include/drv/wd_digest_drv.h |  2 ++
 wd_digest.c                 | 20 ++++++++++++---
 3 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/drv/hisi_sec.c b/drv/hisi_sec.c
index e43ded2..2fd23f3 100644
--- a/drv/hisi_sec.c
+++ b/drv/hisi_sec.c
@@ -73,6 +73,8 @@
 /* The max BD data length is 16M-512B */
 #define MAX_INPUT_DATA_LEN	0xFFFE00
 #define MAX_CCM_AAD_LEN		65279
+#define SHA1_ALIGN_SZ		64
+#define SHA512_ALIGN_SZ		128
 
 #define AUTHPAD_OFFSET		2
 #define AUTHTYPE_OFFSET		6
@@ -1229,31 +1231,24 @@ static int fill_digest_bd2_alg(struct wd_digest_msg *msg,
 static void qm_fill_digest_long_bd(struct wd_digest_msg *msg,
 		struct hisi_sec_sqe *sqe)
 {
-	struct wd_digest_tag *digest_tag = (void *)(uintptr_t)msg->usr_data;
 	__u64 total_bits;
 
 	if (msg->has_next && (msg->iv_bytes == 0)) {
 		/* LONG BD FIRST */
 		sqe->ai_apd_cs = AI_GEN_INNER;
 		sqe->ai_apd_cs |= AUTHPAD_NOPAD << AUTHPAD_OFFSET;
-		msg->iv_bytes = msg->out_bytes;
 	} else if (msg->has_next && (msg->iv_bytes != 0)) {
 		/* LONG BD MIDDLE */
 		sqe->ai_apd_cs = AI_GEN_IVIN_ADDR;
 		sqe->ai_apd_cs |= AUTHPAD_NOPAD << AUTHPAD_OFFSET;
 		sqe->type2.a_ivin_addr = sqe->type2.mac_addr;
-		msg->iv_bytes = msg->out_bytes;
 	} else if (!msg->has_next && (msg->iv_bytes != 0)) {
 		/* LONG BD END */
 		sqe->ai_apd_cs = AI_GEN_IVIN_ADDR;
 		sqe->ai_apd_cs |= AUTHPAD_PAD << AUTHPAD_OFFSET;
 		sqe->type2.a_ivin_addr = sqe->type2.mac_addr;
-		total_bits = digest_tag->long_data_len * BYTE_BITS;
+		total_bits = msg->long_data_len * BYTE_BITS;
 		sqe->type2.long_a_data_len = total_bits;
-		msg->iv_bytes = 0;
-	} else {
-		/* SHORT BD */
-		msg->iv_bytes = 0;
 	}
 }
 
@@ -1282,21 +1277,37 @@ static void parse_digest_bd2(struct hisi_sec_sqe *sqe, struct wd_digest_msg *rec
 #endif
 }
 
-static int digest_len_check(struct wd_digest_msg *msg, enum sec_bd_type type)
+static int digest_long_bd_check(struct wd_digest_msg *msg)
 {
-	if (type == BD_TYPE2 && msg->in_bytes == 0) {
-		WD_ERR("digest bd2 not supports 0 packet!\n");
+	if (msg->alg >= WD_DIGEST_SHA512 && msg->in_bytes % SHA512_ALIGN_SZ)
+		return -WD_EINVAL;
+	else if (msg->in_bytes % SHA1_ALIGN_SZ)
+		return -WD_EINVAL;
+
+	return 0;
+}
+
+static int digest_len_check(struct wd_digest_msg *msg,  enum sec_bd_type type)
+{
+	int ret;
+
+	/*  End BD not need to check the input zero bytes */
+	if (unlikely(type == BD_TYPE2 && (!msg->has_next && msg->in_bytes == 0))) {
+		WD_ERR("kunpeng 920, digest mode not support 0 size!\n");
 		return -WD_EINVAL;
 	}
 
 	if (unlikely(msg->in_bytes > MAX_INPUT_DATA_LEN)) {
-		WD_ERR("failed to check digest input data length!\n");
+		WD_ERR("input data length is too long, size:%u!\n", msg->in_bytes);
 		return -WD_EINVAL;
 	}
 
-	if (unlikely(msg->out_bytes & WORD_ALIGNMENT_MASK)) {
-		WD_ERR("failed to check digest out length!\n");
-		return -WD_EINVAL;
+	if (msg->has_next) {
+		ret = digest_long_bd_check(msg);
+		if (ret) {
+			WD_ERR("input data isn't aligned, size:%u!\n", msg->in_bytes);
+			return -WD_EINVAL;
+		}
 	}
 
 	return 0;
@@ -1435,31 +1446,24 @@ static int fill_digest_bd3_alg(struct wd_digest_msg *msg,
 static void qm_fill_digest_long_bd3(struct wd_digest_msg *msg,
 		struct hisi_sec_sqe3 *sqe)
 {
-	struct wd_digest_tag *digest_tag = (void *)(uintptr_t)msg->usr_data;
 	__u64 total_bits;
 
 	if (msg->has_next && (msg->iv_bytes == 0)) {
 		/* LONG BD FIRST */
 		sqe->auth_mac_key |= AI_GEN_INNER << SEC_AI_GEN_OFFSET_V3;
 		sqe->stream_scene.stream_auth_pad = AUTHPAD_NOPAD;
-		msg->iv_bytes = msg->out_bytes;
 	} else if (msg->has_next && (msg->iv_bytes != 0)) {
 		/* LONG BD MIDDLE */
 		sqe->auth_mac_key |= AI_GEN_IVIN_ADDR << SEC_AI_GEN_OFFSET_V3;
 		sqe->stream_scene.stream_auth_pad = AUTHPAD_NOPAD;
 		sqe->auth_ivin.a_ivin_addr = sqe->mac_addr;
-		msg->iv_bytes = msg->out_bytes;
 	} else if (!msg->has_next && (msg->iv_bytes != 0)) {
 		/* LONG BD END */
 		sqe->auth_mac_key |= AI_GEN_IVIN_ADDR << SEC_AI_GEN_OFFSET_V3;
 		sqe->stream_scene.stream_auth_pad = AUTHPAD_PAD;
 		sqe->auth_ivin.a_ivin_addr = sqe->mac_addr;
-		total_bits = digest_tag->long_data_len * BYTE_BITS;
+		total_bits = msg->long_data_len * BYTE_BITS;
 		sqe->stream_scene.long_a_data_len = total_bits;
-		msg->iv_bytes = 0;
-	} else {
-		/* SHORT BD */
-		msg->iv_bytes = 0;
 	}
 }
 
diff --git a/include/drv/wd_digest_drv.h b/include/drv/wd_digest_drv.h
index 8ccf291..ac3b028 100644
--- a/include/drv/wd_digest_drv.h
+++ b/include/drv/wd_digest_drv.h
@@ -45,6 +45,8 @@ struct wd_digest_msg {
 	__u8 *in;
 	/* output data pointer */
 	__u8 *out;
+	/* total of data for stream mode */
+	__u64 long_data_len;
 };
 
 struct wd_digest_driver {
diff --git a/wd_digest.c b/wd_digest.c
index 22aa98e..c110f7b 100644
--- a/wd_digest.c
+++ b/wd_digest.c
@@ -46,6 +46,10 @@ struct wd_digest_sess {
 	unsigned char		key[MAX_HMAC_KEY_SIZE];
 	__u32			key_bytes;
 	void			*sched_key;
+	/* Notify the BD state */
+	int				state;
+	/* Total of data for stream mode */
+	__u64			 long_data_len;
 };
 
 struct wd_env_config wd_digest_env_config;
@@ -286,11 +290,19 @@ static void fill_request_msg(struct wd_digest_msg *msg,
 	msg->in_bytes = req->in_bytes;
 	msg->out = req->out;
 	msg->out_bytes = req->out_bytes;
-	msg->has_next = req->has_next;
 	msg->data_fmt = req->data_fmt;
+	msg->has_next = req->has_next;
+	sess->long_data_len += req->in_bytes;
+	msg->long_data_len = sess->long_data_len;
+	/* To store the stream bd state */
+	msg->iv_bytes = sess->state;
+	if (req->has_next == 0) {
+		sess->long_data_len = 0;
+		sess->state = 0;
+	}
 }
 
-static int send_recv_sync(struct wd_ctx_internal *ctx,
+static int send_recv_sync(struct wd_ctx_internal *ctx, struct wd_digest_sess *dsess,
 			  struct wd_digest_msg *msg)
 {
 	__u64 recv_cnt = 0;
@@ -320,6 +332,8 @@ static int send_recv_sync(struct wd_ctx_internal *ctx,
 				goto out;
 			}
 		}
+		if (msg->has_next)
+			dsess->state = msg->out_bytes;
 	} while (ret < 0);
 
 out:
@@ -353,7 +367,7 @@ int wd_do_digest_sync(handle_t h_sess, struct wd_digest_req *req)
 		return ret;
 
 	ctx = config->ctxs + idx;
-	ret = send_recv_sync(ctx, &msg);
+	ret = send_recv_sync(ctx, dsess, &msg);
 	req->state = msg.result;
 
 	return ret;
-- 
2.31.1

