linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine
@ 2021-08-13  9:40 Kai Ye
  2021-08-13  9:40 ` [PATCH 1/5] crypto: hisilicon/sec - add ping-pong buffer for ahash Kai Ye
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Kai Ye @ 2021-08-13  9:40 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, linux-kernel, wangzhou1, yekai13

The driver adds hash algorithms, 
sm3, md5, sha1, sha256, sha512.
Add fallback tfm supporting. Modify the driver
as needed. The fuzzing test has been passed.

Kai Ye (5):
  crypto: hisilicon/sec - add ping-pong buffer for ahash
  crypto: hisilicon/sec - add ahash alg features for Kunpeng920
  crypto: hisilicon/sec - support the larger packets for digest mode
  crypto: hisilicon/sec - ahash adapt to Kunpeng930 SQE
  crypto: hisilicon/sec - add fallback tfm supporting for ahash

 drivers/crypto/hisilicon/sec2/sec.h        |   52 +-
 drivers/crypto/hisilicon/sec2/sec_crypto.c | 1315 +++++++++++++++++++++++++++-
 drivers/crypto/hisilicon/sec2/sec_crypto.h |    9 +
 3 files changed, 1359 insertions(+), 17 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/5] crypto: hisilicon/sec - add ping-pong buffer for ahash
  2021-08-13  9:40 [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine Kai Ye
@ 2021-08-13  9:40 ` Kai Ye
  2021-08-13  9:40 ` [PATCH 2/5] crypto: hisilicon/sec - add ahash alg features for Kunpeng920 Kai Ye
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Kai Ye @ 2021-08-13  9:40 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, linux-kernel, wangzhou1, yekai13

For stream mode operations, we don't send data into HW everytime.
We use the pingpong buffer to hold some small packets. The length
of ping-pong buffer is PAGE_SIZE. As well as one TFM supports maximum of
128 streams.

Signed-off-by: Kai Ye <yekai13@huawei.com>
---
 drivers/crypto/hisilicon/sec2/sec.h        | 10 ++++
 drivers/crypto/hisilicon/sec2/sec_crypto.c | 85 ++++++++++++++++++++++++++++++
 drivers/crypto/hisilicon/sec2/sec_crypto.h |  2 +
 3 files changed, 97 insertions(+)

diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h
index 018415b..f72f0fc 100644
--- a/drivers/crypto/hisilicon/sec2/sec.h
+++ b/drivers/crypto/hisilicon/sec2/sec.h
@@ -154,6 +154,16 @@ struct sec_ctx {
 	struct sec_cipher_ctx c_ctx;
 	struct sec_auth_ctx a_ctx;
 	u8 type_supported;
+
+	/*
+	 * For stream mode operations, we don't send data into HW everytime.
+	 * now ahash uses this. To avoid multiple copy, use pingpong buffers.
+	 */
+	struct scatterlist pingpong_sg[SEC_MAX_STREAMS][PINGPONG_BUF_NUM];
+	u8 pingpong_idx[SEC_MAX_STREAMS];
+	u32 pp_data_len[SEC_MAX_STREAMS][PINGPONG_BUF_NUM];
+	struct idr stream_idr;
+	struct mutex stream_idr_lock;
 	struct device *dev;
 };
 
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 6a45bd23..afbe365 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -77,6 +77,8 @@
 #define SEC_TOTAL_PBUF_SZ	(PAGE_SIZE * SEC_PBUF_PAGE_NUM +	\
 			SEC_PBUF_LEFT_SZ)
 
+#define SEC_SID_BUF_LEN		(PAGE_SIZE)
+#define SEC_MAX_AD_SG_NENT	8
 #define SEC_SQE_LEN_RATE	4
 #define SEC_SQE_CFLAG		2
 #define SEC_SQE_AEAD_FLAG	3
@@ -158,6 +160,89 @@ static void sec_free_req_id(struct sec_req *req)
 	mutex_unlock(&qp_ctx->req_lock);
 }
 
+static int sec_alloc_stream_id(struct sec_ctx *ctx)
+{
+	int s_id;
+
+	mutex_lock(&ctx->stream_idr_lock);
+
+	s_id = idr_alloc_cyclic(&ctx->stream_idr, NULL,
+				0, SEC_MAX_STREAMS, GFP_ATOMIC);
+
+	mutex_unlock(&ctx->stream_idr_lock);
+	if (unlikely(s_id < 0))
+		dev_err(ctx->dev, "alloc stream id fail!\n");
+
+	return s_id;
+}
+
+static void sec_free_stream_id(struct sec_ctx *ctx, int stream_id)
+{
+	if (unlikely(stream_id < 0 || stream_id >= SEC_MAX_STREAMS)) {
+		dev_err(ctx->dev, "free stream id invalid!\n");
+		return;
+	}
+
+	mutex_lock(&ctx->stream_idr_lock);
+	idr_remove(&ctx->stream_idr, stream_id);
+	mutex_unlock(&ctx->stream_idr_lock);
+}
+
+/* For stream mode, we pre-create buffer to hold some small packets */
+static int sec_stream_mode_init(struct sec_ctx *ctx)
+{
+	u32 buf_len = SEC_MAX_STREAMS * SEC_SID_BUF_LEN * PINGPONG_BUF_NUM;
+	u32 buf_step = SEC_SID_BUF_LEN * PINGPONG_BUF_NUM;
+	struct device *dev = ctx->dev;
+	unsigned int order, i, j;
+	unsigned long buf;
+	void *temp_buf;
+
+	mutex_init(&ctx->stream_idr_lock);
+	idr_init(&ctx->stream_idr);
+
+	order = get_order(buf_len);
+	if (order > MAX_ORDER) {
+		dev_err(dev, "too large order %u for pingpong buf!\n", order);
+		return -ENOMEM;
+	}
+
+	buf = __get_free_pages(GFP_KERNEL, order);
+	if (!buf) {
+		dev_err(dev, "fail to get pingpong pages!\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * stream 0: | ping buf | pong buf
+	 * stream 1: | ping buf | pong buf
+	 * stream xx: | ping buf | pong buf
+	 * scatterlist ping-pong buffer initiation
+	 */
+	for (j = 0; j < SEC_MAX_STREAMS; j++) {
+		for (i = 0; i < PINGPONG_BUF_NUM; i++) {
+			temp_buf = (void *)(uintptr_t)buf + SEC_SID_BUF_LEN * i;
+
+			sg_init_one(&ctx->pingpong_sg[j][i], temp_buf, SEC_SID_BUF_LEN);
+		}
+		buf = buf + buf_step;
+	}
+
+	return 0;
+}
+
+static void sec_stream_mode_uninit(struct sec_ctx *ctx)
+{
+	struct scatterlist *sgl = &ctx->pingpong_sg[0][0];
+	unsigned int order;
+
+	order = get_order(SEC_SID_BUF_LEN * SEC_MAX_STREAMS * PINGPONG_BUF_NUM);
+
+	free_pages((unsigned long)(uintptr_t)sg_virt(sgl), order);
+
+	idr_destroy(&ctx->stream_idr);
+}
+
 static u8 pre_parse_finished_bd(struct bd_status *status, void *resp)
 {
 	struct sec_sqe *bd = resp;
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h
index 9f71c35..6efe473 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.h
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h
@@ -8,6 +8,8 @@
 #define SEC_IV_SIZE		24
 #define SEC_MAX_KEY_SIZE	64
 #define SEC_COMM_SCENE		0
+#define SEC_MAX_STREAMS		128
+#define PINGPONG_BUF_NUM	2
 #define SEC_MIN_BLOCK_SZ	1
 
 enum sec_calg {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/5] crypto: hisilicon/sec - add ahash alg features for Kunpeng920
  2021-08-13  9:40 [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine Kai Ye
  2021-08-13  9:40 ` [PATCH 1/5] crypto: hisilicon/sec - add ping-pong buffer for ahash Kai Ye
@ 2021-08-13  9:40 ` Kai Ye
  2021-08-21  7:25   ` Herbert Xu
  2021-08-13  9:40 ` [PATCH 3/5] crypto: hisilicon/sec - support the larger packets for digest mode Kai Ye
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Kai Ye @ 2021-08-13  9:40 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, linux-kernel, wangzhou1, yekai13

The length of the first BD and the middle BD is limited by the
hardware. so the pingpong sg be used to assemble packets. Each
time send the pingpong buffer to the hardware when using the
update stream mode. Due to the hardware not be limited for the
final BD. So the diver can combine the last pingpong buffer and
the remain src into a sgl list. then send it to hardware. Also
the driver will output the hash's result in the callback.

Signed-off-by: Kai Ye <yekai13@huawei.com>
---
 drivers/crypto/hisilicon/sec2/sec.h        |  40 +-
 drivers/crypto/hisilicon/sec2/sec_crypto.c | 916 ++++++++++++++++++++++++++++-
 drivers/crypto/hisilicon/sec2/sec_crypto.h |   6 +
 3 files changed, 945 insertions(+), 17 deletions(-)

diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h
index f72f0fc..a68f7a4 100644
--- a/drivers/crypto/hisilicon/sec2/sec.h
+++ b/drivers/crypto/hisilicon/sec2/sec.h
@@ -38,6 +38,28 @@ struct sec_aead_req {
 	struct aead_request *aead_req;
 };
 
+struct sec_ahash_req {
+	struct scatterlist *req_sg;
+	u8 sg_cut_len[SEC_MAX_SG_OF_REMAIN];
+	u32 cut_num;
+	u8 op;
+	u8 done;
+	struct ahash_request *ahash_req;
+	/* Means long hash and ping-pong buffer flag */
+	bool is_stream_mode;
+	u32 req_data_len;
+	/* Currently ping-pong data len */
+	u32 pp_data_len;
+	u64 total_data_len;
+	/* Length of data every bd sent to hardware */
+	u32 block_data_len;
+	int sid;
+
+	struct scatterlist *pp_sg;
+	/* Current pingpong hw sg dma address */
+	dma_addr_t pp_dma;
+};
+
 /* SEC request of Crypto */
 struct sec_req {
 	union {
@@ -49,11 +71,13 @@ struct sec_req {
 
 	/**
 	 * Common parameter of the SEC request.
+	 * ahash, hardware sgl used to hold request's source buffers
 	 */
 	struct hisi_acc_hw_sgl *in;
 	dma_addr_t in_dma;
 	struct sec_cipher_req c_req;
 	struct sec_aead_req aead_req;
+	struct sec_ahash_req hash_req;
 	struct list_head backlog_head;
 
 	int err_type;
@@ -91,8 +115,21 @@ struct sec_auth_ctx {
 	u8 a_key_len;
 	u8 mac_len;
 	u8 a_alg;
+	u32 blk_size;
+	u32 align_sz;
+	dma_addr_t metamac_dma;
+	void *metamac;
 	bool fallback;
+
+	/**
+	 * There are two buffers in the above 'metamac' for each stream.
+	 * -1: no meta-mac (no input hash digest), the 0th buffer is out-mac
+	 * 0: the 0th buffer is meta-mac, the 1th buffer is out-mac
+	 * 1: the 1th buffer is meta-mac, the 0th buffer is out-mac
+	 */
+	char metamac_idx[SEC_MAX_STREAMS];
 	struct crypto_shash *hash_tfm;
+	struct shash_desc *desc;
 	struct crypto_aead *fallback_aead_tfm;
 };
 
@@ -127,7 +164,8 @@ struct sec_qp_ctx {
 
 enum sec_alg_type {
 	SEC_SKCIPHER,
-	SEC_AEAD
+	SEC_AEAD,
+	SEC_AHASH
 };
 
 /* SEC Crypto TFM context which defines queue and cipher .etc relatives */
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index afbe365..35a6ca1 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -9,8 +9,12 @@
 #include <crypto/hash.h>
 #include <crypto/internal/aead.h>
 #include <crypto/internal/des.h>
+#include <crypto/internal/hash.h>
+#include <crypto/md5.h>
+#include <crypto/scatterwalk.h>
 #include <crypto/sha1.h>
 #include <crypto/sha2.h>
+#include <crypto/sm3.h>
 #include <crypto/skcipher.h>
 #include <crypto/xts.h>
 #include <linux/crypto.h>
@@ -36,8 +40,9 @@
 #define SEC_CKEY_OFFSET		9
 #define SEC_CMODE_OFFSET	12
 #define SEC_AKEY_OFFSET         5
-#define SEC_AEAD_ALG_OFFSET     11
+#define SEC_AUTH_ALG_OFFSET	11
 #define SEC_AUTH_OFFSET		6
+#define SEC_APD_OFFSET		2
 
 #define SEC_DE_OFFSET_V3		9
 #define SEC_SCENE_OFFSET_V3	5
@@ -64,6 +69,8 @@
 #define SEC_MAX_MAC_LEN		64
 #define SEC_MAX_AAD_LEN		65535
 #define SEC_TOTAL_MAC_SZ	(SEC_MAX_MAC_LEN * QM_Q_DEPTH)
+#define SEC_HW_MAX_LEN		0xF00000
+#define INVALID_MATEMAC_INDEX	(-1)
 
 #define SEC_PBUF_SZ			512
 #define SEC_PBUF_IV_OFFSET		SEC_PBUF_SZ
@@ -84,7 +91,14 @@
 #define SEC_SQE_AEAD_FLAG	3
 #define SEC_SQE_DONE		0x1
 #define SEC_ICV_ERR		0x2
+#define SEC_SHA_UPDATE		1
+#define SEC_SHA_FINAL		2
+#define SEC_SHA_FINUP		3
+#define SEC_SHA_DIGEST		4
+#define SEC_MAX_DIGEST_SZ	SHA512_DIGEST_SIZE
+#define WORD_ALIGNMENT_MASK	0x3
 #define MIN_MAC_LEN		4
+#define HMAC_HASH_MAX_LEN	20
 #define MAC_LEN_MASK		0x1U
 #define MAX_INPUT_DATA_LEN	0xFFFE00
 #define BITS_MASK		0xFF
@@ -102,10 +116,15 @@
 #define IV_LAST_BYTE_MASK	0xFF
 #define IV_CTR_INIT		0x1
 #define IV_BYTE_OFFSET		0x8
+#define MERGE_SGL_NUM		2
 
 /* Get an en/de-cipher queue cyclically to balance load over queues of TFM */
-static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
+static inline u32 sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
 {
+	if (ctx->alg_type == SEC_AHASH)
+		return (u32)atomic_inc_return(&ctx->enc_qcyclic) %
+				 ctx->sec->ctx_q_num;
+
 	if (req->c_req.encrypt)
 		return (u32)atomic_inc_return(&ctx->enc_qcyclic) %
 				 ctx->hlf_q_num;
@@ -116,7 +135,8 @@ static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
 
 static inline void sec_free_queue_id(struct sec_ctx *ctx, struct sec_req *req)
 {
-	if (req->c_req.encrypt)
+	if (ctx->alg_type == SEC_AHASH ||
+	    (ctx->alg_type != SEC_AHASH && req->c_req.encrypt))
 		atomic_dec(&ctx->enc_qcyclic);
 	else
 		atomic_dec(&ctx->dec_qcyclic);
@@ -498,6 +518,83 @@ static int sec_alloc_pbuf_resource(struct device *dev, struct sec_alg_res *res)
 	return 0;
 }
 
+static int sec_cut_sg_taildata(struct sec_ahash_req *req,
+			       struct scatterlist *sgl, int need_len)
+{
+	u8 *cuts = req->sg_cut_len;
+	int nents = sg_nents(sgl);
+	struct scatterlist *sg;
+	int i;
+
+	if (unlikely(nents > SEC_MAX_SG_OF_REMAIN)) {
+		pr_err("hisi sec2: input scatter list is too long!\n");
+		return -EINVAL;
+	}
+	req->cut_num = 0;
+	for_each_sg(sgl, sg, nents, i) {
+		req->cut_num++;
+
+		if (!need_len) {
+			cuts[i] = 0;
+			break;
+		}
+		if (sg->length < need_len) {
+			cuts[i] = 0;
+			need_len -= sg->length;
+			continue;
+		} else if (sg->length == need_len) {
+			need_len = 0;
+		} else {
+			cuts[i] = sg->length - need_len;
+			sg->length = need_len;
+			need_len = 0;
+		}
+	}
+
+	return 0;
+}
+
+static void sec_restore_sg_tail_data(struct sec_ahash_req *req,
+				     struct scatterlist *sgl)
+{
+	u8 *cuts = req->sg_cut_len;
+	int nents = sg_nents(sgl);
+	struct scatterlist *sg;
+	int i;
+
+	for_each_sg(sgl, sg, nents, i) {
+		if (req->cut_num == i)
+			break;
+		sg->length += cuts[i];
+	}
+
+	req->cut_num = 0;
+}
+
+static int sec_alloc_metamac_buf(struct device *dev, struct sec_ctx *ctx)
+{
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+
+	/* Alloc two block mac memory for every stream */
+	a_ctx->metamac = dma_alloc_coherent(dev, SEC_MAX_DIGEST_SZ *
+			SEC_MAX_STREAMS * PINGPONG_BUF_NUM,
+			&a_ctx->metamac_dma, GFP_KERNEL);
+
+	if (!a_ctx->metamac)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void sec_free_metamac_buf(struct device *dev, struct sec_ctx *ctx)
+{
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+
+	if (a_ctx->metamac)
+		dma_free_coherent(dev, SEC_MAX_DIGEST_SZ * SEC_MAX_STREAMS *
+			PINGPONG_BUF_NUM, a_ctx->metamac, a_ctx->metamac_dma);
+}
+
 static int sec_alg_resource_alloc(struct sec_ctx *ctx,
 				  struct sec_qp_ctx *qp_ctx)
 {
@@ -505,10 +602,11 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
 	struct device *dev = ctx->dev;
 	int ret;
 
-	ret = sec_alloc_civ_resource(dev, res);
-	if (ret)
-		return ret;
-
+	if (ctx->alg_type != SEC_AHASH) {
+		ret = sec_alloc_civ_resource(dev, res);
+		if (ret)
+			return ret;
+	}
 	if (ctx->alg_type == SEC_AEAD) {
 		ret = sec_alloc_aiv_resource(dev, res);
 		if (ret)
@@ -535,7 +633,8 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
 	if (ctx->alg_type == SEC_AEAD)
 		sec_free_aiv_resource(dev, res);
 alloc_aiv_fail:
-	sec_free_civ_resource(dev, res);
+	if (ctx->alg_type != SEC_AHASH)
+		sec_free_civ_resource(dev, res);
 	return ret;
 }
 
@@ -701,21 +800,35 @@ static void sec_cipher_uninit(struct sec_ctx *ctx)
 static int sec_auth_init(struct sec_ctx *ctx)
 {
 	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	struct device *dev = ctx->dev;
+	int ret;
 
-	a_ctx->a_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE,
+	a_ctx->a_key = dma_alloc_coherent(dev, SEC_MAX_KEY_SIZE,
 					  &a_ctx->a_key_dma, GFP_KERNEL);
 	if (!a_ctx->a_key)
 		return -ENOMEM;
 
+	if (ctx->alg_type == SEC_AHASH) {
+		ret = sec_alloc_metamac_buf(dev, ctx);
+		if (ret) {
+			dma_free_coherent(dev, SEC_MAX_KEY_SIZE,
+					  a_ctx->a_key, a_ctx->a_key_dma);
+			return ret;
+		}
+	}
+
 	return 0;
 }
 
 static void sec_auth_uninit(struct sec_ctx *ctx)
 {
 	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	struct device *dev = ctx->dev;
 
+	if (ctx->alg_type == SEC_AHASH)
+		sec_free_metamac_buf(dev, ctx);
 	memzero_explicit(a_ctx->a_key, SEC_MAX_KEY_SIZE);
-	dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE,
+	dma_free_coherent(dev, SEC_MAX_KEY_SIZE,
 			  a_ctx->a_key, a_ctx->a_key_dma);
 }
 
@@ -1101,6 +1214,109 @@ static void sec_skcipher_sgl_unmap(struct sec_ctx *ctx, struct sec_req *req)
 	sec_cipher_unmap(ctx, req, sq->src, sq->dst);
 }
 
+static int sec_ahash_set_key(struct crypto_ahash *tfm, const u8 *key,
+			     const u32 keylen)
+{
+	struct sec_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	struct crypto_shash *shash_tfm = a_ctx->hash_tfm;
+	int blocksize, ret, digestsize;
+
+	blocksize = crypto_shash_blocksize(shash_tfm);
+	digestsize = crypto_shash_digestsize(shash_tfm);
+	if (keylen > blocksize) {
+		/* Must hash the input key */
+		ret = crypto_shash_tfm_digest(shash_tfm, key, keylen, a_ctx->a_key);
+		if (ret) {
+			pr_err("hisi_sec2: ahash digest key error!\n");
+			return -EINVAL;
+		}
+		a_ctx->a_key_len = digestsize;
+	} else {
+		memcpy(a_ctx->a_key, key, keylen);
+		a_ctx->a_key_len = keylen;
+	}
+
+	return 0;
+}
+
+static void sec_hash_unmap(struct sec_ctx *ctx, struct sec_req *req,
+			   struct scatterlist *req_sg)
+{
+	struct sec_ahash_req *sareq = &req->hash_req;
+
+	/* If use ping-pong buffer, chain sgl not need to split */
+	if (sareq->pp_data_len) {
+		if (req->in)
+			hisi_acc_sg_buf_unmap(ctx->dev, sareq->pp_sg, req->in);
+	} else {
+		/* Just unmap the request sgl */
+		if (req->in)
+			hisi_acc_sg_buf_unmap(ctx->dev, req_sg, req->in);
+	}
+}
+
+static int sec_hash_map(struct sec_ctx *ctx, struct sec_req *req,
+			struct scatterlist *req_sg)
+{
+	struct sec_ahash_req *sareq = &req->hash_req;
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+	struct device *dev = ctx->dev;
+
+	req->in = NULL;
+
+	/* If pingpong buffer also has data for the request */
+	if (sareq->pp_data_len && sareq->req_data_len) {
+		/* Chain two sglists together */
+		sg_chain(sareq->pp_sg, MERGE_SGL_NUM, req_sg);
+
+		req->in = hisi_acc_sg_buf_map_to_hw_sgl(dev, sareq->pp_sg,
+							qp_ctx->c_out_pool,
+							req->req_id,
+							&sareq->pp_dma);
+		if (IS_ERR(req->in)) {
+			dev_err(dev, "hash failed to map chain buffers!\n");
+			return PTR_ERR(req->in);
+		}
+	} else if (sareq->pp_data_len && !sareq->req_data_len) {
+		/* Only map pingpong sgl buffers */
+		req->in = hisi_acc_sg_buf_map_to_hw_sgl(dev, sareq->pp_sg,
+							qp_ctx->c_out_pool,
+							req->req_id,
+							&sareq->pp_dma);
+		if (IS_ERR(req->in)) {
+			dev_err(dev, "hash failed to map pingpong buffers!\n");
+			return PTR_ERR(req->in);
+		}
+	} else {
+		/* Map user inputing sgl buffers */
+		req->in = hisi_acc_sg_buf_map_to_hw_sgl(dev, req_sg,
+							qp_ctx->c_out_pool,
+							req->req_id,
+							&sareq->pp_dma);
+		if (IS_ERR(req->in)) {
+			dev_err(dev, "hash failed to map input sgl buffers!\n");
+			return PTR_ERR(req->in);
+		}
+	}
+
+	return 0;
+}
+
+static int sec_ahash_sgl_map(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct ahash_request *ahreq = req->hash_req.ahash_req;
+
+	return sec_hash_map(ctx, req, ahreq->src);
+}
+
+static void sec_ahash_sgl_unmap(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct ahash_request *ahreq = req->hash_req.ahash_req;
+
+	sec_hash_unmap(ctx, req, ahreq->src);
+}
+
 static int sec_aead_aes_set_key(struct sec_cipher_ctx *c_ctx,
 				struct crypto_authenc_keys *keys)
 {
@@ -1406,6 +1622,117 @@ static int sec_skcipher_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req)
 	return 0;
 }
 
+static void sec_ahash_stream_bd_fill(struct sec_auth_ctx *actx,
+				     struct sec_req *req, struct sec_sqe *sqe)
+{
+	struct sec_ahash_req *sareq = &req->hash_req;
+	int sid = sareq->sid;
+	char *idx = &actx->metamac_idx[sid];
+
+	 /*
+	  * Mac addr for ahash result
+	  *
+	  * First BD: idx == -1 && sec_ahash_req->op == SEC_OP_UPDATE
+	  * Middle BD: idx != -1 && sec_ahash_req->op == SEC_OP_UPDATE
+	  * End BD: sec_ahash_req->op == SEC_OP_FINAL ||
+	  *              sec_ahash_req->op == SEC_OP_FINUP
+	  * NOT stream BD, idx == -1, && sec_ahash_req->op == SEC_OP_FINAL ||
+	  *              sec_ahash_req->op == SEC_OP_FINUP
+	  */
+	if (*idx != (char)-1) {
+		sqe->type2.a_ivin_addr = cpu_to_le64(actx->metamac_dma +
+				(sid + *idx) * SEC_MAX_DIGEST_SZ);
+
+		sqe->type2.mac_addr = cpu_to_le64(actx->metamac_dma +
+		(sid + ((unsigned char)*idx ^ 0x1)) * SEC_MAX_DIGEST_SZ);
+		/* Middle BD */
+		if (sareq->op == SEC_SHA_UPDATE) {
+			sqe->ai_apd_cs = AIGEN_NOGEN;
+			sqe->ai_apd_cs |= AUTHPAD_NOPAD << SEC_APD_OFFSET;
+		}
+	} else {
+		/* No meta-mac */
+		sqe->type2.mac_addr = cpu_to_le64(actx->metamac_dma +
+				sid * SEC_MAX_DIGEST_SZ);
+		/* First BD */
+		if (sareq->op == SEC_SHA_UPDATE) {
+			sqe->ai_apd_cs = AIGEN_GEN;
+			sqe->ai_apd_cs |= AUTHPAD_NOPAD << SEC_APD_OFFSET;
+			sareq->is_stream_mode = true;
+		}
+	}
+
+	/* End BD */
+	if ((sareq->op == SEC_SHA_FINAL || sareq->op == SEC_SHA_FINUP) &&
+	    sareq->is_stream_mode) {
+		sqe->type2.a_ivin_addr = cpu_to_le64(actx->metamac_dma +
+			(sid + *idx) * SEC_MAX_DIGEST_SZ);
+
+		sqe->type2.mac_addr = cpu_to_le64(actx->metamac_dma + (sid +
+		((unsigned char)*idx ^ 0x1)) * SEC_MAX_DIGEST_SZ);
+
+		sqe->ai_apd_cs = AIGEN_NOGEN;
+		sqe->ai_apd_cs |= AUTHPAD_PAD << SEC_APD_OFFSET;
+
+		/* Fill the total hash data length */
+		sqe->type2.long_a_data_len = cpu_to_le64(sareq->total_data_len <<
+							0x3);
+		sareq->is_stream_mode = false;
+	}
+}
+
+static void sec_ahash_data_len_fill(struct sec_ahash_req *sareq,
+				    struct sec_sqe *sec_sqe)
+{
+	if ((sareq->op == SEC_SHA_UPDATE || sareq->op == SEC_SHA_FINAL) &&
+	    sareq->pp_data_len)
+		sec_sqe->type2.alen_ivllen = cpu_to_le32(sareq->block_data_len);
+	else if (!sareq->pp_data_len && sareq->op == SEC_SHA_FINAL)
+		sec_sqe->type2.alen_ivllen = cpu_to_le32(0);
+	else
+		sec_sqe->type2.alen_ivllen = cpu_to_le32(sareq->req_data_len);
+}
+
+static int sec_ahash_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_auth_ctx *actx = &ctx->a_ctx;
+	struct sec_sqe *sec_sqe = &req->sec_sqe;
+	struct sec_ahash_req *sareq = &req->hash_req;
+	dma_addr_t pp_dma = sareq->pp_dma;
+	u8 scene, sa_type;
+
+	sareq->done = 0;
+	memset(sec_sqe, 0, sizeof(struct sec_sqe));
+	sec_sqe->type_cipher_auth = SEC_BD_TYPE2;
+
+	scene = SEC_IPSEC_SCENE << SEC_SCENE_OFFSET;
+	sa_type = SEC_SGL << SEC_SRC_SGL_OFFSET;
+	/* de:1~2 bits| scene:3~6 bits| sa_type:~7 bit, de = 0 means disable */
+	sec_sqe->sds_sa_type = (scene | sa_type);
+
+	sec_sqe->type2.data_src_addr = cpu_to_le64(pp_dma);
+
+	sec_sqe->type2.a_key_addr = cpu_to_le64(actx->a_key_dma);
+
+	sec_sqe->type2.mac_key_alg = cpu_to_le32(actx->mac_len /
+						 SEC_SQE_LEN_RATE);
+	sec_sqe->type2.mac_key_alg |=
+			cpu_to_le32((u32)((actx->a_key_len) /
+			SEC_SQE_LEN_RATE) << SEC_AKEY_OFFSET);
+
+	sec_sqe->type2.mac_key_alg |=
+			cpu_to_le32((u32)(actx->a_alg) << SEC_AUTH_ALG_OFFSET);
+
+	sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
+
+	sec_ahash_data_len_fill(sareq, sec_sqe);
+
+	sec_ahash_stream_bd_fill(actx, req, sec_sqe);
+	sec_sqe->type2.tag = cpu_to_le16((u16)req->req_id);
+
+	return 0;
+}
+
 /* increment counter (128-bit int) */
 static void ctr_iv_inc(__u8 *counter, __u8 bits, __u32 nums)
 {
@@ -1500,6 +1827,71 @@ static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
 	sk_req->base.complete(&sk_req->base, err);
 }
 
+static void sec_ahash_callback(struct sec_ctx *ctx, struct sec_req *req, int err)
+{
+	struct sec_ahash_req *sareq = &req->hash_req;
+	struct ahash_request *areq = sareq->ahash_req;
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+	struct ahash_request *backlog_ahash_req;
+	struct sec_req *backlog_req;
+	int sid = sareq->sid;
+	char *idx = &a_ctx->metamac_idx[sid];
+
+	sec_free_req_id(req);
+
+	/* Restore the original request */
+	sec_restore_sg_tail_data(sareq, areq->src);
+
+	while (1) {
+		backlog_req = sec_back_req_clear(ctx, qp_ctx);
+		if (!backlog_req)
+			break;
+
+		backlog_ahash_req = backlog_req->hash_req.ahash_req;
+		backlog_ahash_req->base.complete(&backlog_ahash_req->base,
+						-EINPROGRESS);
+		atomic64_inc(&ctx->sec->debug.dfx.recv_busy_cnt);
+	}
+
+	/*
+	 * As update, just change the meta mac buffer,
+	 * -1 is invalid metamac index
+	 */
+	if (sareq->op == SEC_SHA_UPDATE) {
+		if (*idx == (char)-1)
+			*idx = 0;
+		else
+			*idx = (unsigned char)*idx ^ 1;
+	} else {
+		/*
+		 * This hash is finished, op == final or finup,
+		 * output digest value
+		 */
+		if (*idx == (char)-1) {
+			memcpy(areq->result, a_ctx->metamac +
+				sid * SEC_MAX_DIGEST_SZ,
+				a_ctx->mac_len);
+		} else {
+			*idx = (unsigned char)*idx ^ 0x1;
+			memcpy(areq->result, a_ctx->metamac +
+				(sid + *idx) * SEC_MAX_DIGEST_SZ,
+				a_ctx->mac_len);
+		}
+		*idx = -1;
+		sareq->total_data_len = 0;
+		/* The hash stream is end */
+		sec_free_stream_id(ctx, sid);
+	}
+
+	sareq->done = SEC_SQE_DONE;
+
+	sareq->req_data_len = 0;
+	sareq->pp_data_len = 0;
+
+	areq->base.complete(&areq->base, err);
+}
+
 static void set_aead_auth_iv(struct sec_ctx *ctx, struct sec_req *req)
 {
 	struct aead_request *aead_req = req->aead_req.aead_req;
@@ -1621,6 +2013,11 @@ static void sec_auth_bd_fill_xcm_v3(struct sec_auth_ctx *ctx, int dir,
 	sqe3->mac_addr = cpu_to_le64(a_req->out_mac_dma);
 }
 
+static void sec_ahash_transfer(struct sec_ctx *ctx, struct sec_req *req)
+{
+	/* No need to do anything */
+}
+
 static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
 			       struct sec_req *req, struct sec_sqe *sec_sqe)
 {
@@ -1638,7 +2035,7 @@ static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
 			SEC_SQE_LEN_RATE) << SEC_AKEY_OFFSET);
 
 	sec_sqe->type2.mac_key_alg |=
-			cpu_to_le32((u32)(ctx->a_alg) << SEC_AEAD_ALG_OFFSET);
+			cpu_to_le32((u32)(ctx->a_alg) << SEC_AUTH_ALG_OFFSET);
 
 	if (dir) {
 		sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
@@ -1816,9 +2213,11 @@ static int sec_process(struct sec_ctx *ctx, struct sec_req *req)
 		goto err_uninit_req;
 
 	/* Output IV as decrypto */
-	if (!req->c_req.encrypt && (ctx->c_ctx.c_mode == SEC_CMODE_CBC ||
-	    ctx->c_ctx.c_mode == SEC_CMODE_CTR))
-		sec_update_iv(req, ctx->alg_type);
+	if (ctx->alg_type != SEC_AHASH) {
+		if (!req->c_req.encrypt && (ctx->c_ctx.c_mode == SEC_CMODE_CBC ||
+		    ctx->c_ctx.c_mode == SEC_CMODE_CTR))
+			sec_update_iv(req, ctx->alg_type);
+	}
 
 	ret = ctx->req_op->bd_send(ctx, req);
 	if (unlikely((ret != -EBUSY && ret != -EINPROGRESS) ||
@@ -1866,6 +2265,16 @@ static const struct sec_req_op sec_aead_req_ops = {
 	.process	= sec_process,
 };
 
+static const struct sec_req_op sec_ahash_req_ops = {
+	.buf_map	= sec_ahash_sgl_map,
+	.buf_unmap	= sec_ahash_sgl_unmap,
+	.do_transfer	= sec_ahash_transfer,
+	.bd_fill	= sec_ahash_bd_fill,
+	.bd_send	= sec_bd_send,
+	.callback	= sec_ahash_callback,
+	.process	= sec_process,
+};
+
 static const struct sec_req_op sec_skcipher_req_ops_v3 = {
 	.buf_map	= sec_skcipher_sgl_map,
 	.buf_unmap	= sec_skcipher_sgl_unmap,
@@ -2027,6 +2436,428 @@ static void sec_aead_xcm_ctx_exit(struct crypto_aead *tfm)
 	sec_aead_exit(tfm);
 }
 
+static int sec_ahash_req_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *areq = &sreq->hash_req;
+	struct sec_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	char *tfm_alg_name;
+	int sid;
+
+	sreq->ctx = ctx;
+
+	tfm_alg_name = tfm->base.__crt_alg->cra_name;
+	a_ctx->mac_len = crypto_ahash_digestsize(tfm);
+	a_ctx->align_sz = SEC_SHA1_ALIGN_SZ;
+
+	switch (a_ctx->mac_len) {
+	case MD5_DIGEST_SIZE:
+		a_ctx->blk_size = MD5_HMAC_BLOCK_SIZE;
+		a_ctx->a_alg = SEC_A_HMAC_MD5;
+		break;
+	case SHA1_DIGEST_SIZE:
+		a_ctx->blk_size = SHA1_BLOCK_SIZE;
+		a_ctx->a_alg = SEC_A_HMAC_SHA1;
+		break;
+	case SHA256_DIGEST_SIZE:
+		a_ctx->blk_size = SHA256_BLOCK_SIZE;
+		if (strcmp(tfm_alg_name, "hmac(sha256)"))
+			a_ctx->a_alg = SEC_A_HMAC_SM3;
+		else
+			a_ctx->a_alg = SEC_A_HMAC_SHA256;
+		break;
+	case SHA512_DIGEST_SIZE:
+		a_ctx->blk_size = SHA512_BLOCK_SIZE;
+		a_ctx->a_alg = SEC_A_HMAC_SHA512;
+		a_ctx->align_sz = SEC_SHA512_ALIGN_SZ;
+		break;
+	default:
+		pr_err("hisi_sec2: mac length error: %u\n", a_ctx->mac_len);
+		return -EINVAL;
+	}
+
+	sid = sec_alloc_stream_id(ctx);
+	if (unlikely(sid < 0))
+		return sid;
+
+	ctx->pingpong_idx[sid] = 0;
+	ctx->pp_data_len[sid][0] = 0;
+	areq->req_sg = req->src;
+
+	/*
+	 * Init ping-pong buffer, At the first time, we use the first
+	 * ping sg buffer
+	 */
+	areq->pp_sg = &ctx->pingpong_sg[sid][0];
+	areq->sid = sid;
+	areq->total_data_len = 0;
+	areq->block_data_len = 0;
+	areq->ahash_req = req;
+	areq->is_stream_mode = false;
+	areq->done = 0;
+	areq->op = 0;
+	ctx->a_ctx.metamac_idx[sid] = -1;
+
+	return 0;
+}
+
+static int sec_ahash_process(struct ahash_request *req)
+{
+	struct scatterlist *curr_pp_sg, *next_pp_sg;
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *ahreq = &sreq->hash_req;
+	struct scatterlist *req_sg = req->src;
+	struct sec_ctx *ctx = sreq->ctx;
+	u32 align_sz = ctx->a_ctx.align_sz;
+	int nents = sg_nents(req_sg);
+	u32 remain, data_len;
+	int sid = ahreq->sid;
+	u8 current_idx;
+	int ret;
+
+	current_idx = ctx->pingpong_idx[sid];
+	curr_pp_sg = ahreq->pp_sg;
+
+	data_len = ctx->pp_data_len[sid][current_idx];
+
+	/* Check if current data length is aligned */
+	remain = (data_len + req->nbytes) % align_sz;
+
+	if (remain && ahreq->op == SEC_SHA_UPDATE) {
+		u8 idx = current_idx ^ 0x1;
+
+		next_pp_sg = &ctx->pingpong_sg[idx][sid];
+
+		/* If the request's data is enough for cutting the remain size */
+		if (req->nbytes > remain) {
+			/*
+			 * Copy end 'remain' data of the current request into
+			 * next pingpong buffer for the next operation
+			 */
+			sg_pcopy_to_buffer(req_sg, nents, sg_virt(next_pp_sg), remain,
+					   req->nbytes - remain);
+			/*
+			 * Update the pingpong buffer data length of the next
+			 * pingpong buffer
+			 */
+			ctx->pp_data_len[sid][idx] = remain;
+			/*
+			 * Save need data from req, cut has been copied to next
+			 * pingpong buffer data
+			 */
+			ret = sec_cut_sg_taildata(ahreq, req_sg, req->nbytes - remain);
+			if (unlikely(ret))
+				return ret;
+
+			ahreq->req_data_len = req->nbytes - remain;
+			ahreq->pp_data_len = data_len;
+			ahreq->block_data_len = data_len + req->nbytes - remain;
+		} else if (req->nbytes == remain) {
+			/*
+			 * Copy all data in current request to next
+			 * pingpong buffer
+			 */
+			sg_pcopy_to_buffer(req_sg, nents, sg_virt(next_pp_sg), remain, 0);
+			ahreq->req_data_len = 0;
+			ahreq->pp_data_len = data_len;
+			ahreq->block_data_len = data_len;
+			/* Updata next buff data length */
+			ctx->pp_data_len[sid][idx] = remain;
+		} else if (req->nbytes < remain) {
+			u8 buf_minus = remain - req->nbytes;
+			/*
+			 * Copy part data of current pingpong buffer and all
+			 * data of the request to next pingpong buffer.
+			 */
+			memcpy(sg_virt(next_pp_sg), sg_virt(curr_pp_sg) + data_len - buf_minus,
+			       buf_minus);
+			/*
+			 * Current request source scatterlist has no data
+			 * since they are moved into next pp buffer
+			 */
+			ahreq->req_data_len = 0;
+
+			/* Update current data length */
+			ctx->pp_data_len[sid][current_idx] -= buf_minus;
+
+			/* Update current request's pp data length */
+			ahreq->pp_data_len = data_len - buf_minus;
+
+			sg_pcopy_to_buffer(req_sg, nents, sg_virt(next_pp_sg) +
+					   buf_minus, req->nbytes, 0);
+			ctx->pp_data_len[sid][idx] = req->nbytes + buf_minus;
+			ahreq->block_data_len = data_len - buf_minus;
+		}
+
+		/* Update ping-pong index for the next operation */
+		ctx->pingpong_idx[sid] = idx;
+	} else {
+		ahreq->req_data_len = req->nbytes;
+		ahreq->pp_data_len = data_len;
+		ahreq->block_data_len = data_len;
+	}
+
+	if (unlikely(ahreq->req_data_len + ahreq->pp_data_len >
+		  SEC_HW_MAX_LEN)) {
+		pr_err("Too long input buffer for Hisilicon SEC2!\n");
+		return -EINVAL;
+	}
+
+	if (ahreq->op == SEC_SHA_FINAL)
+		/* There is no data in the final request */
+		ahreq->total_data_len += ahreq->pp_data_len;
+	else
+		ahreq->total_data_len += ahreq->req_data_len +
+					 ahreq->pp_data_len;
+	/*
+	 * Now, all the input data is ready, there may be two scatterlists,
+	 * and send them with at least one scatterlist into the hardware
+	 */
+	return ctx->req_op->process(ctx, sreq);
+}
+
+static int sec_ahash_update(struct ahash_request *req)
+{
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *sareq = &sreq->hash_req;
+	struct scatterlist *pingpong_sg;
+	struct sec_ctx *ctx = sreq->ctx;
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	int sid = sareq->sid;
+	u32 data_len;
+	u8 idx;
+
+	if (unlikely(req->nbytes > SEC_HW_MAX_LEN)) {
+		dev_err_ratelimited(ctx->dev, "too long input for updating!\n");
+		return -EINVAL;
+	}
+
+	/* Just update as no data */
+	if (!req->nbytes)
+		return 0;
+
+	if (unlikely(sid >= SEC_MAX_STREAMS || sid < 0)) {
+		pr_err("hisilicon SEC2 stream id %d error!\n", sid);
+		return -EINVAL;
+	}
+
+	idx = ctx->pingpong_idx[sid];
+
+	pingpong_sg = &ctx->pingpong_sg[sid][idx];
+	data_len = ctx->pp_data_len[sid][idx];
+
+	sareq->op = SEC_SHA_UPDATE;
+	sareq->pp_sg = pingpong_sg;
+
+	/* The pingpong buffer can hold the input of this request */
+	if (data_len + req->nbytes <= SEC_SID_BUF_LEN) {
+		scatterwalk_map_and_copy(sg_virt(pingpong_sg) + data_len,
+					 req->src, 0, req->nbytes, 0);
+		ctx->pp_data_len[sid][idx] += req->nbytes;
+
+		return 0;
+	}
+
+	return sec_ahash_process(req);
+}
+
+static int sec_ahash_final(struct ahash_request *req)
+{
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *sareq = &sreq->hash_req;
+	struct sec_ctx *ctx = sreq->ctx;
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	u32 sid = sareq->sid;
+	u8 idx;
+
+	sareq->op = SEC_SHA_FINAL;
+	if (sareq->is_stream_mode) {
+		idx = ctx->pingpong_idx[sid];
+		sareq->pp_sg = &ctx->pingpong_sg[sid][idx];
+	}
+
+	return sec_ahash_process(req);
+}
+
+static void stream_hash_wait(struct sec_ahash_req *sareq)
+{
+	while (sareq->is_stream_mode && sareq->done != SEC_SQE_DONE)
+		cpu_relax();
+}
+
+static int sec_ahash_finup(struct ahash_request *req)
+{
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *sareq = &sreq->hash_req;
+	struct sec_ctx *ctx = sreq->ctx;
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	int nents = sg_nents(req->src);
+	struct scatterlist *sg;
+	int i = 0;
+	int ret;
+
+	if (sareq->op == SEC_SHA_UPDATE) {
+		if (unlikely(req->nbytes > SEC_HW_MAX_LEN)) {
+			dev_err_ratelimited(ctx->dev, "too long input for update+finup!\n");
+			return -EINVAL;
+		}
+
+		ret = sec_ahash_update(req);
+		/* Update process return -EINPROGRESS not return failed */
+		if (unlikely(ret == -EINVAL)) {
+			pr_err("ahash update+finup mode last update process is error!\n");
+			return ret;
+		}
+
+		stream_hash_wait(sareq);
+
+		return sec_ahash_final(req);
+	}
+
+	return sec_ahash_process(req);
+}
+
+static int sec_ahash_digest(struct ahash_request *req)
+{
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *sareq = &sreq->hash_req;
+	int nents = sg_nents(req->src);
+	struct sec_auth_ctx *a_ctx;
+	struct scatterlist *sg;
+	struct sec_ctx *ctx;
+	int ret, i;
+
+	ret = sec_ahash_req_init(req);
+	if (ret)
+		return -EINVAL;
+
+	ctx = sreq->ctx;
+	a_ctx = &ctx->a_ctx;
+
+	sareq->op = SEC_SHA_DIGEST;
+
+	return sec_ahash_finup(req);
+}
+
+static int sec_ahash_export(struct ahash_request *req, void *out)
+{
+	/*
+	 * This function dumps the
+	 * entire state of the ongoing transformation into a provided block of
+	 * data so it can be @import'ed back later on.
+	 */
+	struct sec_req *sreq = ahash_request_ctx(req);
+
+	memcpy(out, sreq, sizeof(struct sec_req));
+	return 0;
+}
+
+static int sec_ahash_import(struct ahash_request *req, const void *in)
+{
+	/*
+	 * Import partial state of the transformation. This function loads the
+	 * entire state of the ongoing transformation from a provided block of
+	 * data so the transformation can continue from this point onward.
+	 */
+	struct sec_req *sreq = ahash_request_ctx(req);
+
+	memcpy(sreq, in, sizeof(struct sec_req));
+	return 0;
+}
+
+static void sec_ahash_tfm_uninit(struct crypto_tfm *tfm)
+{
+	struct sec_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	sec_release_fallback_shash(ctx->a_ctx.fallback_ahash_tfm, ctx->a_ctx.desc);
+	crypto_free_shash(ctx->a_ctx.hash_tfm);
+	sec_stream_mode_uninit(ctx);
+	sec_auth_uninit(ctx);
+	sec_ctx_base_uninit(ctx);
+}
+
+static int sec_ahash_tfm_init(struct crypto_tfm *tfm, const char *ahash_name)
+{
+	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+	struct sec_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+	char hmac_ahash_name[HMAC_HASH_MAX_LEN];
+	int ret;
+
+	ctx->alg_type = SEC_AHASH;
+	crypto_ahash_set_reqsize(ahash, sizeof(struct sec_req));
+
+	ret = sec_ctx_base_init(ctx);
+	if (ret) {
+		pr_err("hisi_sec2: sec hash ctx base init error!\n");
+		return ret;
+	}
+
+	ret = sec_auth_init(ctx);
+	if (ret)
+		goto err_auth_init;
+
+	ctx->type_supported = SEC_BD_TYPE2;
+	ctx->req_op = &sec_ahash_req_ops;
+
+	/* Support 128 streams/threads per TFM, memory for small packets */
+	ret = sec_stream_mode_init(ctx);
+	if (ret < 0)
+		goto err_mem_init;
+
+	a_ctx->fallback = false;
+	a_ctx->hash_tfm = crypto_alloc_shash(ahash_name, 0, 0);
+	if (IS_ERR(a_ctx->hash_tfm)) {
+		dev_err(ctx->dev, "ahash driver alloc shash error!\n");
+		ret = PTR_ERR(a_ctx->hash_tfm);
+		goto err_alloc_shash;
+	}
+
+	snprintf(hmac_ahash_name, HMAC_HASH_MAX_LEN, "hmac(%s)", ahash_name);
+
+	ret = sec_alloc_fallback_shash(hmac_ahash_name, &a_ctx->fallback_ahash_tfm, &a_ctx->desc);
+	if (ret)
+		goto err_alloc_hmac;
+
+	return 0;
+err_alloc_hmac:
+	crypto_free_shash(ctx->a_ctx.hash_tfm);
+err_alloc_shash:
+	sec_stream_mode_uninit(ctx);
+err_mem_init:
+	sec_auth_uninit(ctx);
+err_auth_init:
+	sec_ctx_base_uninit(ctx);
+	return ret;
+}
+
+static int sec_ahash_md5_init(struct crypto_tfm *tfm)
+{
+	return sec_ahash_tfm_init(tfm, "md5");
+}
+
+static int sec_ahash_sm3_init(struct crypto_tfm *tfm)
+{
+	return sec_ahash_tfm_init(tfm, "sm3");
+}
+
+static int sec_ahash_sha1_init(struct crypto_tfm *tfm)
+{
+	return sec_ahash_tfm_init(tfm, "sha1");
+}
+
+static int sec_ahash_sha256_init(struct crypto_tfm *tfm)
+{
+	return sec_ahash_tfm_init(tfm, "sha256");
+}
+
+static int sec_ahash_sha512_init(struct crypto_tfm *tfm)
+{
+	return sec_ahash_tfm_init(tfm, "sha512");
+}
+
 static int sec_aead_sha1_ctx_init(struct crypto_aead *tfm)
 {
 	return sec_aead_ctx_init(tfm, "sha1");
@@ -2042,7 +2873,6 @@ static int sec_aead_sha512_ctx_init(struct crypto_aead *tfm)
 	return sec_aead_ctx_init(tfm, "sha512");
 }
 
-
 static int sec_skcipher_cryptlen_ckeck(struct sec_ctx *ctx,
 	struct sec_req *sreq)
 {
@@ -2129,7 +2959,7 @@ static int sec_skcipher_soft_crypto(struct sec_ctx *ctx,
 
 	skcipher_request_set_sync_tfm(subreq, c_ctx->fbtfm);
 
-	/* software need sync mode to do crypto */
+	/* Software need sync mode to do crypto */
 	skcipher_request_set_callback(subreq, sreq->base.flags,
 				      NULL, NULL);
 	skcipher_request_set_crypt(subreq, sreq->src, sreq->dst,
@@ -2481,6 +3311,49 @@ static struct aead_alg sec_aeads_v3[] = {
 		     SEC_AIV_SIZE, AES_BLOCK_SIZE)
 };
 
+#define SEC_AHASH_ALG(sec_cra_name, digest_size, blksize, ahash_cra_init) \
+{\
+	.halg = {\
+		.digestsize = digest_size,\
+		.statesize = sizeof(struct sec_req),\
+		.base = {\
+			.cra_name = sec_cra_name,\
+			.cra_driver_name = "hisi_sec_"sec_cra_name,\
+			.cra_priority = 300,\
+			.cra_flags = CRYPTO_ALG_ASYNC |\
+				CRYPTO_ALG_KERN_DRIVER_ONLY |\
+				CRYPTO_ALG_NEED_FALLBACK,\
+			.cra_blocksize = blksize,\
+			.cra_ctxsize = sizeof(struct sec_ctx),\
+			.cra_alignmask = 3,\
+			.cra_init = ahash_cra_init,\
+			.cra_exit = sec_ahash_tfm_uninit,\
+			.cra_module = THIS_MODULE,\
+		},\
+	},\
+	.init = sec_ahash_req_init,\
+	.update = sec_ahash_update,\
+	.final = sec_ahash_final,\
+	.finup = sec_ahash_finup,\
+	.digest = sec_ahash_digest,\
+	.export = sec_ahash_export,\
+	.import = sec_ahash_import,\
+	.setkey = sec_ahash_set_key,\
+}
+
+static struct ahash_alg sec_ahashes[] = {
+	SEC_AHASH_ALG("hmac(md5)", MD5_DIGEST_SIZE,
+		      MD5_HMAC_BLOCK_SIZE, sec_ahash_md5_init),
+	SEC_AHASH_ALG("hmac(sm3)", SM3_DIGEST_SIZE,
+		      SM3_BLOCK_SIZE, sec_ahash_sm3_init),
+	SEC_AHASH_ALG("hmac(sha1)", SHA1_DIGEST_SIZE,
+		      SHA1_BLOCK_SIZE, sec_ahash_sha1_init),
+	SEC_AHASH_ALG("hmac(sha256)", SHA256_DIGEST_SIZE,
+		      SHA256_BLOCK_SIZE, sec_ahash_sha256_init),
+	SEC_AHASH_ALG("hmac(sha512)", SHA512_DIGEST_SIZE,
+		      SHA512_BLOCK_SIZE, sec_ahash_sha512_init),
+};
+
 int sec_register_to_crypto(struct hisi_qm *qm)
 {
 	int ret;
@@ -2506,8 +3379,17 @@ int sec_register_to_crypto(struct hisi_qm *qm)
 		if (ret)
 			goto reg_aead_v3_fail;
 	}
+
+	ret = crypto_register_ahashes(sec_ahashes, ARRAY_SIZE(sec_ahashes));
+	if (ret)
+		goto reg_ahash_fail;
+
 	return ret;
 
+reg_ahash_fail:
+	if (qm->ver > QM_HW_V2)
+		crypto_unregister_aeads(sec_aeads_v3,
+					ARRAY_SIZE(sec_aeads_v3));
 reg_aead_v3_fail:
 	crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
 reg_aead_fail:
@@ -2522,6 +3404,8 @@ int sec_register_to_crypto(struct hisi_qm *qm)
 
 void sec_unregister_from_crypto(struct hisi_qm *qm)
 {
+	crypto_unregister_ahashes(sec_ahashes, ARRAY_SIZE(sec_ahashes));
+
 	if (qm->ver > QM_HW_V2)
 		crypto_unregister_aeads(sec_aeads_v3,
 					ARRAY_SIZE(sec_aeads_v3));
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h
index 6efe473..2157b98 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.h
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h
@@ -8,7 +8,11 @@
 #define SEC_IV_SIZE		24
 #define SEC_MAX_KEY_SIZE	64
 #define SEC_COMM_SCENE		0
+#define SEC_IPSEC_SCENE		1
 #define SEC_MAX_STREAMS		128
+#define SEC_SHA1_ALIGN_SZ	64
+#define SEC_SHA512_ALIGN_SZ	128
+#define SEC_MAX_SG_OF_REMAIN	8
 #define PINGPONG_BUF_NUM	2
 #define SEC_MIN_BLOCK_SZ	1
 
@@ -21,7 +25,9 @@ enum sec_calg {
 enum sec_hash_alg {
 	SEC_A_HMAC_SHA1   = 0x10,
 	SEC_A_HMAC_SHA256 = 0x11,
+	SEC_A_HMAC_MD5    = 0x12,
 	SEC_A_HMAC_SHA512 = 0x15,
+	SEC_A_HMAC_SM3	  = 0x26,
 };
 
 enum sec_mac_len {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/5] crypto: hisilicon/sec - support the larger packets for digest mode
  2021-08-13  9:40 [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine Kai Ye
  2021-08-13  9:40 ` [PATCH 1/5] crypto: hisilicon/sec - add ping-pong buffer for ahash Kai Ye
  2021-08-13  9:40 ` [PATCH 2/5] crypto: hisilicon/sec - add ahash alg features for Kunpeng920 Kai Ye
@ 2021-08-13  9:40 ` Kai Ye
  2021-08-13  9:40 ` [PATCH 4/5] crypto: hisilicon/sec - ahash adapt to Kunpeng930 SQE Kai Ye
  2021-08-13  9:40 ` [PATCH 5/5] crypto: hisilicon/sec - add fallback tfm supporting for ahash Kai Ye
  4 siblings, 0 replies; 7+ messages in thread
From: Kai Ye @ 2021-08-13  9:40 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, linux-kernel, wangzhou1, yekai13

Support the larger packets inputing for digest mode. By split the larger
packet, the driver input one block size packet to the hardware every time.
Setting one block size is PAGE_SIZE(4K). Based on the long hash feature,
the soft waits until the previous packet is complete and then sends the
next packet.

Signed-off-by: Kai Ye <yekai13@huawei.com>
---
 drivers/crypto/hisilicon/sec2/sec_crypto.c | 76 ++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 35a6ca1..2c6cfa7 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -2719,6 +2719,80 @@ static int sec_ahash_finup(struct ahash_request *req)
 	return sec_ahash_process(req);
 }
 
+static int digest_hardware_update(struct sec_req *sreq, struct scatterlist *src,
+				  u32 start, u32 nbytes)
+{
+	struct sec_ahash_req *sareq = &sreq->hash_req;
+	struct scatterlist *pingpong_sg;
+	struct sec_ctx *ctx = sreq->ctx;
+	int nents = sg_nents(src);
+	int sid = sareq->sid;
+	u8 idx;
+
+	idx = ctx->pingpong_idx[sid];
+	pingpong_sg = &ctx->pingpong_sg[sid][idx];
+
+	sareq->op = SEC_SHA_UPDATE;
+	sareq->pp_sg = pingpong_sg;
+
+	/* The pingpong buffer can hold the one block input of this request */
+	sg_pcopy_to_buffer(src, nents, sg_virt(pingpong_sg), nbytes, start);
+	ctx->pp_data_len[sid][idx] = nbytes;
+
+	sareq->req_data_len = 0;
+	sareq->pp_data_len = nbytes;
+	sareq->block_data_len = nbytes;
+	sareq->total_data_len += nbytes;
+
+	return ctx->req_op->process(ctx, sreq);
+}
+
+static int sec_ahash_larger_digest(struct ahash_request *req)
+{
+	struct sec_req *sreq = ahash_request_ctx(req);
+	struct sec_ahash_req *sareq = &sreq->hash_req;
+	u32 input_len = req->nbytes;
+	struct scatterlist *pingpong_sg;
+	struct sec_ctx *ctx = sreq->ctx;
+	u32 sid = sareq->sid;
+	u8 idx = ctx->pingpong_idx[sid];
+	u32 start = 0;
+	int ret;
+
+	while (input_len > SEC_SID_BUF_LEN) {
+		/* setting one block size is PAGE_SIZE */
+		req->nbytes = SEC_SID_BUF_LEN;
+		input_len -= SEC_SID_BUF_LEN;
+
+		ret = digest_hardware_update(sreq, req->src, start,
+					     req->nbytes);
+		if (unlikely(ret == -EINVAL)) {
+			pr_err("ahash digest: hardware update process is error!\n");
+			return ret;
+		}
+
+		stream_hash_wait(sareq);
+
+		start += SEC_SID_BUF_LEN;
+	}
+
+	/* last packet send to the hardware */
+	req->nbytes = input_len;
+	sareq->req_data_len = 0;
+
+	pingpong_sg = &ctx->pingpong_sg[sid][idx];
+	sg_pcopy_to_buffer(req->src, sg_nents(req->src), sg_virt(pingpong_sg),
+			   input_len, start);
+	ctx->pp_data_len[sid][idx] = input_len;
+	sareq->pp_data_len = input_len;
+	sareq->block_data_len = input_len;
+	sareq->total_data_len += input_len;
+
+	sareq->op = SEC_SHA_FINAL;
+
+	return ctx->req_op->process(ctx, sreq);
+}
+
 static int sec_ahash_digest(struct ahash_request *req)
 {
 	struct sec_req *sreq = ahash_request_ctx(req);
@@ -2735,6 +2809,8 @@ static int sec_ahash_digest(struct ahash_request *req)
 
 	ctx = sreq->ctx;
 	a_ctx = &ctx->a_ctx;
+	if (req->nbytes > SEC_HW_MAX_LEN)
+		return sec_ahash_larger_digest(req);
 
 	sareq->op = SEC_SHA_DIGEST;
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/5] crypto: hisilicon/sec - ahash adapt to Kunpeng930 SQE
  2021-08-13  9:40 [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine Kai Ye
                   ` (2 preceding siblings ...)
  2021-08-13  9:40 ` [PATCH 3/5] crypto: hisilicon/sec - support the larger packets for digest mode Kai Ye
@ 2021-08-13  9:40 ` Kai Ye
  2021-08-13  9:40 ` [PATCH 5/5] crypto: hisilicon/sec - add fallback tfm supporting for ahash Kai Ye
  4 siblings, 0 replies; 7+ messages in thread
From: Kai Ye @ 2021-08-13  9:40 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, linux-kernel, wangzhou1, yekai13

The SEC ahash needs to supporting next generation of SEC
accelerator hardware. So add the new BD filling process.

Signed-off-by: Kai Ye <yekai13@huawei.com>
---
 drivers/crypto/hisilicon/sec2/sec_crypto.c | 137 ++++++++++++++++++++++++++++-
 drivers/crypto/hisilicon/sec2/sec_crypto.h |   1 +
 2 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 2c6cfa7..85defc1 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -55,6 +55,8 @@
 #define SEC_AUTH_ALG_OFFSET_V3	15
 #define SEC_CIPHER_AUTH_V3	0xbf
 #define SEC_AUTH_CIPHER_V3	0x40
+#define SEC_AI_GEN_OFFSET_V3	2
+
 #define SEC_FLAG_OFFSET		7
 #define SEC_FLAG_MASK		0x0780
 #define SEC_TYPE_MASK		0x0F
@@ -1681,6 +1683,69 @@ static void sec_ahash_stream_bd_fill(struct sec_auth_ctx *actx,
 	}
 }
 
+static void sec_ahash_stream_bd_fill_v3(struct sec_auth_ctx *actx,
+					struct sec_req *req,
+					struct sec_sqe3 *sqe3)
+{
+	struct sec_ahash_req *sareq = &req->hash_req;
+	int sid = sareq->sid;
+	char *idx = &actx->metamac_idx[sid];
+
+	 /**
+	  * Mac addr for ahash result
+	  *
+	  * First BD: idx == -1 && sec_ahash_req->op == SEC_OP_UPDATE
+	  * Middle BD: idx != -1 && sec_ahash_req->op == SEC_OP_UPDATE
+	  * End BD: sec_ahash_req->op == SEC_OP_FINAL ||
+	  *              sec_ahash_req->op == SEC_OP_FINUP
+	  * NOT stream BD, idx == -1, && sec_ahash_req->op == SEC_OP_FINAL ||
+	  *              sec_ahash_req->op == SEC_OP_FINUP
+	  */
+	if (*idx != (char)-1) {
+		sqe3->auth_ivin.a_ivin_addr = cpu_to_le64(actx->metamac_dma +
+				(sid + *idx) * SEC_MAX_DIGEST_SZ);
+
+		sqe3->mac_addr = cpu_to_le64(actx->metamac_dma +
+		(sid + ((unsigned char)*idx ^ 0x1)) * SEC_MAX_DIGEST_SZ);
+		/* Middle BD */
+		if (sareq->op == SEC_SHA_UPDATE) {
+			sqe3->auth_mac_key |= cpu_to_le32((u32)AIGEN_NOGEN <<
+							SEC_AI_GEN_OFFSET_V3);
+			sqe3->stream_scene.stream_auth_pad = AUTHPAD_NOPAD;
+		}
+	} else {
+		/* no meta-mac */
+		sqe3->mac_addr = cpu_to_le64(actx->metamac_dma +
+				sid * SEC_MAX_DIGEST_SZ);
+		/* First BD */
+		if (sareq->op == SEC_SHA_UPDATE) {
+			sqe3->auth_mac_key |= cpu_to_le32((u32)AIGEN_GEN <<
+							SEC_AI_GEN_OFFSET_V3);
+			sqe3->stream_scene.stream_auth_pad = AUTHPAD_NOPAD;
+			sareq->is_stream_mode = true;
+		}
+	}
+
+	/* End BD */
+	if ((sareq->op == SEC_SHA_FINAL || sareq->op == SEC_SHA_FINUP) &&
+	    sareq->is_stream_mode) {
+		sqe3->auth_ivin.a_ivin_addr = cpu_to_le64(actx->metamac_dma +
+					(sid + *idx) * SEC_MAX_DIGEST_SZ);
+
+		sqe3->mac_addr = cpu_to_le64(actx->metamac_dma + (sid +
+			((unsigned char)*idx ^ 0x1)) * SEC_MAX_DIGEST_SZ);
+
+		sqe3->auth_mac_key |= cpu_to_le32((u32)AIGEN_NOGEN <<
+							SEC_AI_GEN_OFFSET_V3);
+		sqe3->stream_scene.stream_auth_pad = AUTHPAD_PAD;
+
+		/* Fill the total hash data length */
+		sqe3->stream_scene.long_a_data_len =
+				cpu_to_le64(sareq->total_data_len << 0x3);
+		sareq->is_stream_mode = false;
+	}
+}
+
 static void sec_ahash_data_len_fill(struct sec_ahash_req *sareq,
 				    struct sec_sqe *sec_sqe)
 {
@@ -1693,6 +1758,18 @@ static void sec_ahash_data_len_fill(struct sec_ahash_req *sareq,
 		sec_sqe->type2.alen_ivllen = cpu_to_le32(sareq->req_data_len);
 }
 
+static void sec_ahash_data_len_fill_v3(struct sec_ahash_req *sareq,
+				       struct sec_sqe3 *sec_sqe3)
+{
+	if ((sareq->op == SEC_SHA_UPDATE || sareq->op == SEC_SHA_FINAL) &&
+	    sareq->pp_data_len)
+		sec_sqe3->a_len_key = cpu_to_le32(sareq->block_data_len);
+	else if (!sareq->pp_data_len && sareq->op == SEC_SHA_FINAL)
+		sec_sqe3->a_len_key = cpu_to_le32(0);
+	else
+		sec_sqe3->a_len_key = cpu_to_le32(sareq->req_data_len);
+}
+
 static int sec_ahash_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
 {
 	struct sec_auth_ctx *actx = &ctx->a_ctx;
@@ -1733,6 +1810,47 @@ static int sec_ahash_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
 	return 0;
 }
 
+static int sec_ahash_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_auth_ctx *actx = &ctx->a_ctx;
+	struct sec_sqe3 *sec_sqe3 = &req->sec_sqe3;
+	struct sec_ahash_req *sareq = &req->hash_req;
+	dma_addr_t pp_dma = sareq->pp_dma;
+	u32 bd_param = 0;
+
+	memset(sec_sqe3, 0, sizeof(struct sec_sqe3));
+
+	bd_param |= SEC_SGL << SEC_SRC_SGL_OFFSET_V3;
+	bd_param |= SEC_STREAM_SCENE << SEC_SCENE_OFFSET_V3;
+	bd_param |= SEC_BD_TYPE3;
+	sec_sqe3->bd_param = cpu_to_le32(bd_param);
+
+	sec_sqe3->data_src_addr = cpu_to_le64(pp_dma);
+
+	sec_sqe3->a_key_addr = cpu_to_le64(actx->a_key_dma);
+
+	sec_sqe3->auth_mac_key = cpu_to_le32((u32)SEC_AUTH_TYPE1);
+
+	sec_sqe3->auth_mac_key |=
+			cpu_to_le32((u32)(actx->mac_len /
+			SEC_SQE_LEN_RATE) << SEC_MAC_OFFSET_V3);
+
+	sec_sqe3->auth_mac_key |=
+			cpu_to_le32((u32)((actx->a_key_len) /
+			SEC_SQE_LEN_RATE) << SEC_AKEY_OFFSET_V3);
+
+	sec_sqe3->auth_mac_key |=
+			cpu_to_le32((u32)(actx->a_alg) << SEC_AUTH_ALG_OFFSET_V3);
+
+	sec_ahash_data_len_fill_v3(sareq, sec_sqe3);
+
+	sec_ahash_stream_bd_fill_v3(actx, req, sec_sqe3);
+
+	sec_sqe3->tag = cpu_to_le64((unsigned long)(uintptr_t)req);
+
+	return 0;
+}
+
 /* increment counter (128-bit int) */
 static void ctr_iv_inc(__u8 *counter, __u8 bits, __u32 nums)
 {
@@ -2295,6 +2413,16 @@ static const struct sec_req_op sec_aead_req_ops_v3 = {
 	.process	= sec_process,
 };
 
+static const struct sec_req_op sec_ahash_req_ops_v3 = {
+	.buf_map	= sec_ahash_sgl_map,
+	.buf_unmap	= sec_ahash_sgl_unmap,
+	.do_transfer	= sec_ahash_transfer,
+	.bd_fill	= sec_ahash_bd_fill_v3,
+	.bd_send	= sec_bd_send,
+	.callback	= sec_ahash_callback,
+	.process	= sec_process,
+};
+
 static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm)
 {
 	struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
@@ -2875,8 +3003,13 @@ static int sec_ahash_tfm_init(struct crypto_tfm *tfm, const char *ahash_name)
 	if (ret)
 		goto err_auth_init;
 
-	ctx->type_supported = SEC_BD_TYPE2;
-	ctx->req_op = &sec_ahash_req_ops;
+	if (ctx->sec->qm.ver < QM_HW_V3) {
+		ctx->type_supported = SEC_BD_TYPE2;
+		ctx->req_op = &sec_ahash_req_ops;
+	} else {
+		ctx->type_supported = SEC_BD_TYPE3;
+		ctx->req_op = &sec_ahash_req_ops_v3;
+	}
 
 	/* Support 128 streams/threads per TFM, memory for small packets */
 	ret = sec_stream_mode_init(ctx);
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h
index 2157b98..9f117b5 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.h
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h
@@ -9,6 +9,7 @@
 #define SEC_MAX_KEY_SIZE	64
 #define SEC_COMM_SCENE		0
 #define SEC_IPSEC_SCENE		1
+#define SEC_STREAM_SCENE	0x7
 #define SEC_MAX_STREAMS		128
 #define SEC_SHA1_ALIGN_SZ	64
 #define SEC_SHA512_ALIGN_SZ	128
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/5] crypto: hisilicon/sec - add fallback tfm supporting for ahash
  2021-08-13  9:40 [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine Kai Ye
                   ` (3 preceding siblings ...)
  2021-08-13  9:40 ` [PATCH 4/5] crypto: hisilicon/sec - ahash adapt to Kunpeng930 SQE Kai Ye
@ 2021-08-13  9:40 ` Kai Ye
  4 siblings, 0 replies; 7+ messages in thread
From: Kai Ye @ 2021-08-13  9:40 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, linux-kernel, wangzhou1, yekai13

1. The Kunpeng920 hardware not support 0 packet size for digest mode.
2. The hardware only supports 4-byte alignment key inputing.
Due to the above hardware limitations, So the driver needs
to setting the soft fallback hash tfm for user.

Signed-off-by: Kai Ye <yekai13@huawei.com>
---
 drivers/crypto/hisilicon/sec2/sec.h        |   2 +
 drivers/crypto/hisilicon/sec2/sec_crypto.c | 105 +++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h
index a68f7a4..7a81dcc 100644
--- a/drivers/crypto/hisilicon/sec2/sec.h
+++ b/drivers/crypto/hisilicon/sec2/sec.h
@@ -129,6 +129,8 @@ struct sec_auth_ctx {
 	 */
 	char metamac_idx[SEC_MAX_STREAMS];
 	struct crypto_shash *hash_tfm;
+	/* alloc soft hash tfm for not support parameter */
+	struct crypto_shash *fallback_ahash_tfm;
 	struct shash_desc *desc;
 	struct crypto_aead *fallback_aead_tfm;
 };
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 85defc1..91853f8 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -1224,6 +1224,17 @@ static int sec_ahash_set_key(struct crypto_ahash *tfm, const u8 *key,
 	struct crypto_shash *shash_tfm = a_ctx->hash_tfm;
 	int blocksize, ret, digestsize;
 
+	ret = crypto_shash_setkey(a_ctx->fallback_ahash_tfm, key, keylen);
+	if (ret) {
+		pr_err("hisi_sec2: fallback shash set key error!\n");
+		return ret;
+	}
+
+	if (keylen & WORD_ALIGNMENT_MASK) {
+		a_ctx->fallback = true;
+		return 0;
+	}
+
 	blocksize = crypto_shash_blocksize(shash_tfm);
 	digestsize = crypto_shash_digestsize(shash_tfm);
 	if (keylen > blocksize) {
@@ -2575,6 +2586,8 @@ static int sec_ahash_req_init(struct ahash_request *req)
 	int sid;
 
 	sreq->ctx = ctx;
+	if (unlikely(a_ctx->fallback))
+		return crypto_shash_init(a_ctx->desc);
 
 	tfm_alg_name = tfm->base.__crt_alg->cra_name;
 	a_ctx->mac_len = crypto_ahash_digestsize(tfm);
@@ -2746,6 +2759,27 @@ static int sec_ahash_process(struct ahash_request *req)
 	return ctx->req_op->process(ctx, sreq);
 }
 
+static int sec_shash_update(struct ahash_request *req, struct sec_auth_ctx *ctx)
+{
+	int nents = sg_nents(req->src);
+	int total_sgl_len = 0;
+	struct scatterlist *sg;
+	int ret, i;
+
+	for_each_sg(req->src, sg, nents, i) {
+		ret = crypto_shash_update(ctx->desc, sg_virt(sg), sg->length);
+		if (ret) {
+			pr_err("ahash use fallback ahash is error!\n");
+			return ret;
+		}
+		total_sgl_len += sg->length;
+		if (total_sgl_len == req->nbytes)
+			break;
+	}
+
+	return 0;
+}
+
 static int sec_ahash_update(struct ahash_request *req)
 {
 	struct sec_req *sreq = ahash_request_ctx(req);
@@ -2757,6 +2791,9 @@ static int sec_ahash_update(struct ahash_request *req)
 	u32 data_len;
 	u8 idx;
 
+	if (unlikely(a_ctx->fallback))
+		return sec_shash_update(req, a_ctx);
+
 	if (unlikely(req->nbytes > SEC_HW_MAX_LEN)) {
 		dev_err_ratelimited(ctx->dev, "too long input for updating!\n");
 		return -EINVAL;
@@ -2800,6 +2837,9 @@ static int sec_ahash_final(struct ahash_request *req)
 	u32 sid = sareq->sid;
 	u8 idx;
 
+	if (unlikely(a_ctx->fallback))
+		return crypto_shash_final(a_ctx->desc, req->result);
+
 	sareq->op = SEC_SHA_FINAL;
 	if (sareq->is_stream_mode) {
 		idx = ctx->pingpong_idx[sid];
@@ -2826,6 +2866,20 @@ static int sec_ahash_finup(struct ahash_request *req)
 	int i = 0;
 	int ret;
 
+	if (unlikely(a_ctx->fallback)) {
+		for_each_sg(req->src, sg, nents, i) {
+			if (i + 1 == sg_nents(req->src))
+				return crypto_shash_finup(a_ctx->desc, sg_virt(sg),
+							sg->length, req->result);
+
+			ret = crypto_shash_update(a_ctx->desc, sg_virt(sg), sg->length);
+			if (ret) {
+				pr_err("ahash use fallback ahash is error!\n");
+				return ret;
+			}
+		}
+	}
+
 	if (sareq->op == SEC_SHA_UPDATE) {
 		if (unlikely(req->nbytes > SEC_HW_MAX_LEN)) {
 			dev_err_ratelimited(ctx->dev, "too long input for update+finup!\n");
@@ -2940,6 +2994,23 @@ static int sec_ahash_digest(struct ahash_request *req)
 	if (req->nbytes > SEC_HW_MAX_LEN)
 		return sec_ahash_larger_digest(req);
 
+	/* kunpeng 920, digest mode not support input 0 size */
+	if (unlikely(ctx->type_supported == SEC_BD_TYPE2 && !req->nbytes))
+		return crypto_shash_digest(a_ctx->desc, sg_virt(req->src), 0,
+								req->result);
+
+	if (unlikely(a_ctx->fallback)) {
+		for_each_sg(req->src, sg, nents, i) {
+			ret = crypto_shash_update(a_ctx->desc, sg_virt(sg),
+						  sg->length);
+			if (ret) {
+				pr_err("ahash use fallback ahash is error!\n");
+				return ret;
+			}
+		}
+
+		return crypto_shash_final(a_ctx->desc, req->result);
+	}
 	sareq->op = SEC_SHA_DIGEST;
 
 	return sec_ahash_finup(req);
@@ -2971,6 +3042,40 @@ static int sec_ahash_import(struct ahash_request *req, const void *in)
 	return 0;
 }
 
+static void sec_release_fallback_shash(struct crypto_shash *tfm,
+				       struct shash_desc *desc)
+{
+	crypto_free_shash(tfm);
+	kfree(desc);
+}
+
+static int sec_alloc_fallback_shash(const char *driver,
+				    struct crypto_shash **tfm_ret,
+				    struct shash_desc **desc_ret)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	int ret;
+
+	tfm = crypto_alloc_shash(driver, 0, CRYPTO_ALG_NEED_FALLBACK);
+	if (IS_ERR(tfm)) {
+		pr_err("ahash driver alloc hmac shash error!\n");
+		ret = PTR_ERR(tfm);
+		return ret;
+	}
+	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+	if (!desc) {
+		crypto_free_shash(tfm);
+		return -ENOMEM;
+	}
+	desc->tfm = tfm;
+
+	*tfm_ret = tfm;
+	*desc_ret = desc;
+
+	return 0;
+}
+
 static void sec_ahash_tfm_uninit(struct crypto_tfm *tfm)
 {
 	struct sec_ctx *ctx = crypto_tfm_ctx(tfm);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/5] crypto: hisilicon/sec - add ahash alg features for Kunpeng920
  2021-08-13  9:40 ` [PATCH 2/5] crypto: hisilicon/sec - add ahash alg features for Kunpeng920 Kai Ye
@ 2021-08-21  7:25   ` Herbert Xu
  0 siblings, 0 replies; 7+ messages in thread
From: Herbert Xu @ 2021-08-21  7:25 UTC (permalink / raw)
  To: Kai Ye; +Cc: linux-crypto, linux-kernel, wangzhou1

On Fri, Aug 13, 2021 at 05:40:23PM +0800, Kai Ye wrote:
>
> +static int sec_ahash_import(struct ahash_request *req, const void *in)
> +{
> +	/*
> +	 * Import partial state of the transformation. This function loads the
> +	 * entire state of the ongoing transformation from a provided block of
> +	 * data so the transformation can continue from this point onward.
> +	 */
> +	struct sec_req *sreq = ahash_request_ctx(req);
> +
> +	memcpy(sreq, in, sizeof(struct sec_req));
> +	return 0;
> +}

Please explain how this works given that you've got pointers in
struct sec_req?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-08-21  7:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-13  9:40 [PATCH 0/5] crypto: hisilicon - supports hash algorithm for SEC engine Kai Ye
2021-08-13  9:40 ` [PATCH 1/5] crypto: hisilicon/sec - add ping-pong buffer for ahash Kai Ye
2021-08-13  9:40 ` [PATCH 2/5] crypto: hisilicon/sec - add ahash alg features for Kunpeng920 Kai Ye
2021-08-21  7:25   ` Herbert Xu
2021-08-13  9:40 ` [PATCH 3/5] crypto: hisilicon/sec - support the larger packets for digest mode Kai Ye
2021-08-13  9:40 ` [PATCH 4/5] crypto: hisilicon/sec - ahash adapt to Kunpeng930 SQE Kai Ye
2021-08-13  9:40 ` [PATCH 5/5] crypto: hisilicon/sec - add fallback tfm supporting for ahash Kai Ye

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).