| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  * Hash function and HMAC support for StarFive driver | 
 |  * | 
 |  * Copyright (c) 2022 StarFive Technology | 
 |  * | 
 |  */ | 
 |  | 
 | #include <crypto/engine.h> | 
 | #include <crypto/internal/hash.h> | 
 | #include <crypto/scatterwalk.h> | 
 | #include "jh7110-cryp.h" | 
 | #include <linux/amba/pl080.h> | 
 | #include <linux/clk.h> | 
 | #include <linux/dma-direct.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/iopoll.h> | 
 | #include <linux/kernel.h> | 
 | #include <linux/module.h> | 
 | #include <linux/platform_device.h> | 
 | #include <linux/pm_runtime.h> | 
 | #include <linux/reset.h> | 
 |  | 
 | #define STARFIVE_HASH_REGS_OFFSET	0x300 | 
 | #define STARFIVE_HASH_SHACSR		(STARFIVE_HASH_REGS_OFFSET + 0x0) | 
 | #define STARFIVE_HASH_SHAWDR		(STARFIVE_HASH_REGS_OFFSET + 0x4) | 
 | #define STARFIVE_HASH_SHARDR		(STARFIVE_HASH_REGS_OFFSET + 0x8) | 
 | #define STARFIVE_HASH_SHAWSR		(STARFIVE_HASH_REGS_OFFSET + 0xC) | 
 | #define STARFIVE_HASH_SHAWLEN3		(STARFIVE_HASH_REGS_OFFSET + 0x10) | 
 | #define STARFIVE_HASH_SHAWLEN2		(STARFIVE_HASH_REGS_OFFSET + 0x14) | 
 | #define STARFIVE_HASH_SHAWLEN1		(STARFIVE_HASH_REGS_OFFSET + 0x18) | 
 | #define STARFIVE_HASH_SHAWLEN0		(STARFIVE_HASH_REGS_OFFSET + 0x1C) | 
 | #define STARFIVE_HASH_SHAWKR		(STARFIVE_HASH_REGS_OFFSET + 0x20) | 
 | #define STARFIVE_HASH_SHAWKLEN		(STARFIVE_HASH_REGS_OFFSET + 0x24) | 
 |  | 
 | #define STARFIVE_HASH_BUFLEN		SHA512_BLOCK_SIZE | 
 | #define STARFIVE_HASH_RESET		0x2 | 
 |  | 
 | static inline int starfive_hash_wait_busy(struct starfive_cryp_dev *cryp) | 
 | { | 
 | 	u32 status; | 
 |  | 
 | 	return readl_relaxed_poll_timeout(cryp->base + STARFIVE_HASH_SHACSR, status, | 
 | 					  !(status & STARFIVE_HASH_BUSY), 10, 100000); | 
 | } | 
 |  | 
 | static inline int starfive_hash_wait_hmac_done(struct starfive_cryp_dev *cryp) | 
 | { | 
 | 	u32 status; | 
 |  | 
 | 	return readl_relaxed_poll_timeout(cryp->base + STARFIVE_HASH_SHACSR, status, | 
 | 					  (status & STARFIVE_HASH_HMAC_DONE), 10, 100000); | 
 | } | 
 |  | 
 | static inline int starfive_hash_wait_key_done(struct starfive_cryp_ctx *ctx) | 
 | { | 
 | 	struct starfive_cryp_dev *cryp = ctx->cryp; | 
 | 	u32 status; | 
 |  | 
 | 	return readl_relaxed_poll_timeout(cryp->base + STARFIVE_HASH_SHACSR, status, | 
 | 					  (status & STARFIVE_HASH_KEY_DONE), 10, 100000); | 
 | } | 
 |  | 
 | static int starfive_hash_hmac_key(struct starfive_cryp_ctx *ctx) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ctx->rctx; | 
 | 	struct starfive_cryp_dev *cryp = ctx->cryp; | 
 | 	int klen = ctx->keylen, loop; | 
 | 	unsigned int *key = (unsigned int *)ctx->key; | 
 | 	unsigned char *cl; | 
 |  | 
 | 	writel(ctx->keylen, cryp->base + STARFIVE_HASH_SHAWKLEN); | 
 |  | 
 | 	rctx->csr.hash.hmac = 1; | 
 | 	rctx->csr.hash.key_flag = 1; | 
 |  | 
 | 	writel(rctx->csr.hash.v, cryp->base + STARFIVE_HASH_SHACSR); | 
 |  | 
 | 	for (loop = 0; loop < klen / sizeof(unsigned int); loop++, key++) | 
 | 		writel(*key, cryp->base + STARFIVE_HASH_SHAWKR); | 
 |  | 
 | 	if (klen & 0x3) { | 
 | 		cl = (unsigned char *)key; | 
 | 		for (loop = 0; loop < (klen & 0x3); loop++, cl++) | 
 | 			writeb(*cl, cryp->base + STARFIVE_HASH_SHAWKR); | 
 | 	} | 
 |  | 
 | 	if (starfive_hash_wait_key_done(ctx)) | 
 | 		return dev_err_probe(cryp->dev, -ETIMEDOUT, "starfive_hash_wait_key_done error\n"); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void starfive_hash_start(struct starfive_cryp_dev *cryp) | 
 | { | 
 | 	union starfive_hash_csr csr; | 
 |  | 
 | 	csr.v = readl(cryp->base + STARFIVE_HASH_SHACSR); | 
 | 	csr.firstb = 0; | 
 | 	csr.final = 1; | 
 | 	writel(csr.v, cryp->base + STARFIVE_HASH_SHACSR); | 
 | } | 
 |  | 
 | static void starfive_hash_dma_callback(void *param) | 
 | { | 
 | 	struct starfive_cryp_dev *cryp = param; | 
 |  | 
 | 	complete(&cryp->dma_done); | 
 | } | 
 |  | 
 | static void starfive_hash_dma_init(struct starfive_cryp_dev *cryp) | 
 | { | 
 | 	cryp->cfg_in.src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES; | 
 | 	cryp->cfg_in.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 
 | 	cryp->cfg_in.src_maxburst = cryp->dma_maxburst; | 
 | 	cryp->cfg_in.dst_maxburst = cryp->dma_maxburst; | 
 | 	cryp->cfg_in.dst_addr = cryp->phys_base + STARFIVE_ALG_FIFO_OFFSET; | 
 |  | 
 | 	dmaengine_slave_config(cryp->tx, &cryp->cfg_in); | 
 |  | 
 | 	init_completion(&cryp->dma_done); | 
 | } | 
 |  | 
 | static int starfive_hash_dma_xfer(struct starfive_cryp_dev *cryp, | 
 | 				  struct scatterlist *sg) | 
 | { | 
 | 	struct dma_async_tx_descriptor *in_desc; | 
 | 	union starfive_alg_cr alg_cr; | 
 | 	int ret = 0; | 
 |  | 
 | 	alg_cr.v = 0; | 
 | 	alg_cr.start = 1; | 
 | 	alg_cr.hash_dma_en = 1; | 
 | 	writel(alg_cr.v, cryp->base + STARFIVE_ALG_CR_OFFSET); | 
 |  | 
 | 	writel(sg_dma_len(sg), cryp->base + STARFIVE_DMA_IN_LEN_OFFSET); | 
 | 	sg_dma_len(sg) = ALIGN(sg_dma_len(sg), sizeof(u32)); | 
 |  | 
 | 	in_desc = dmaengine_prep_slave_sg(cryp->tx, sg, 1, DMA_MEM_TO_DEV, | 
 | 					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | 
 | 	if (!in_desc) { | 
 | 		ret = -EINVAL; | 
 | 		goto end; | 
 | 	} | 
 |  | 
 | 	reinit_completion(&cryp->dma_done); | 
 | 	in_desc->callback = starfive_hash_dma_callback; | 
 | 	in_desc->callback_param = cryp; | 
 |  | 
 | 	dmaengine_submit(in_desc); | 
 | 	dma_async_issue_pending(cryp->tx); | 
 |  | 
 | 	if (!wait_for_completion_timeout(&cryp->dma_done, | 
 | 					 msecs_to_jiffies(1000))) | 
 | 		ret = -ETIMEDOUT; | 
 |  | 
 | end: | 
 | 	alg_cr.v = 0; | 
 | 	alg_cr.clear = 1; | 
 | 	writel(alg_cr.v, cryp->base + STARFIVE_ALG_CR_OFFSET); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int starfive_hash_copy_hash(struct ahash_request *req) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); | 
 | 	int count, *data; | 
 | 	int mlen; | 
 |  | 
 | 	if (!req->result) | 
 | 		return 0; | 
 |  | 
 | 	mlen = rctx->digsize / sizeof(u32); | 
 | 	data = (u32 *)req->result; | 
 |  | 
 | 	for (count = 0; count < mlen; count++) | 
 | 		put_unaligned(readl(ctx->cryp->base + STARFIVE_HASH_SHARDR), | 
 | 			      &data[count]); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void starfive_hash_done_task(struct starfive_cryp_dev *cryp) | 
 | { | 
 | 	int err = cryp->err; | 
 |  | 
 | 	if (!err) | 
 | 		err = starfive_hash_copy_hash(cryp->req.hreq); | 
 |  | 
 | 	crypto_finalize_hash_request(cryp->engine, cryp->req.hreq, err); | 
 | } | 
 |  | 
 | static int starfive_hash_one_request(struct crypto_engine *engine, void *areq) | 
 | { | 
 | 	struct ahash_request *req = container_of(areq, struct ahash_request, | 
 | 						 base); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); | 
 | 	struct starfive_cryp_request_ctx *rctx = ctx->rctx; | 
 | 	struct starfive_cryp_dev *cryp = ctx->cryp; | 
 | 	struct scatterlist *tsg; | 
 | 	int ret, src_nents, i; | 
 |  | 
 | 	writel(STARFIVE_HASH_RESET, cryp->base + STARFIVE_HASH_SHACSR); | 
 |  | 
 | 	if (starfive_hash_wait_busy(cryp)) | 
 | 		return dev_err_probe(cryp->dev, -ETIMEDOUT, "Error resetting hardware\n"); | 
 |  | 
 | 	rctx->csr.hash.v = 0; | 
 | 	rctx->csr.hash.mode = ctx->hash_mode; | 
 |  | 
 | 	if (ctx->is_hmac) { | 
 | 		ret = starfive_hash_hmac_key(ctx); | 
 | 		if (ret) | 
 | 			return ret; | 
 | 	} else { | 
 | 		rctx->csr.hash.start = 1; | 
 | 		rctx->csr.hash.firstb = 1; | 
 | 		writel(rctx->csr.hash.v, cryp->base + STARFIVE_HASH_SHACSR); | 
 | 	} | 
 |  | 
 | 	/* No input message, get digest and end. */ | 
 | 	if (!rctx->total) | 
 | 		goto hash_start; | 
 |  | 
 | 	starfive_hash_dma_init(cryp); | 
 |  | 
 | 	for_each_sg(rctx->in_sg, tsg, rctx->in_sg_len, i) { | 
 | 		src_nents = dma_map_sg(cryp->dev, tsg, 1, DMA_TO_DEVICE); | 
 | 		if (src_nents == 0) | 
 | 			return dev_err_probe(cryp->dev, -ENOMEM, | 
 | 					     "dma_map_sg error\n"); | 
 |  | 
 | 		ret = starfive_hash_dma_xfer(cryp, tsg); | 
 | 		dma_unmap_sg(cryp->dev, tsg, 1, DMA_TO_DEVICE); | 
 | 		if (ret) | 
 | 			return ret; | 
 | 	} | 
 |  | 
 | hash_start: | 
 | 	starfive_hash_start(cryp); | 
 |  | 
 | 	if (starfive_hash_wait_busy(cryp)) | 
 | 		return dev_err_probe(cryp->dev, -ETIMEDOUT, "Error generating digest\n"); | 
 |  | 
 | 	if (ctx->is_hmac) | 
 | 		cryp->err = starfive_hash_wait_hmac_done(cryp); | 
 |  | 
 | 	starfive_hash_done_task(cryp); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int starfive_hash_init(struct ahash_request *req) | 
 | { | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 |  | 
 | 	ahash_request_set_tfm(&rctx->ahash_fbk_req, ctx->ahash_fbk); | 
 | 	ahash_request_set_callback(&rctx->ahash_fbk_req, | 
 | 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP, | 
 | 				   req->base.complete, req->base.data); | 
 |  | 
 | 	ahash_request_set_crypt(&rctx->ahash_fbk_req, req->src, | 
 | 				req->result, req->nbytes); | 
 |  | 
 | 	return crypto_ahash_init(&rctx->ahash_fbk_req); | 
 | } | 
 |  | 
 | static int starfive_hash_update(struct ahash_request *req) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 |  | 
 | 	ahash_request_set_tfm(&rctx->ahash_fbk_req, ctx->ahash_fbk); | 
 | 	ahash_request_set_callback(&rctx->ahash_fbk_req, | 
 | 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP, | 
 | 				   req->base.complete, req->base.data); | 
 |  | 
 | 	ahash_request_set_crypt(&rctx->ahash_fbk_req, req->src, | 
 | 				req->result, req->nbytes); | 
 |  | 
 | 	return crypto_ahash_update(&rctx->ahash_fbk_req); | 
 | } | 
 |  | 
 | static int starfive_hash_final(struct ahash_request *req) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 |  | 
 | 	ahash_request_set_tfm(&rctx->ahash_fbk_req, ctx->ahash_fbk); | 
 | 	ahash_request_set_callback(&rctx->ahash_fbk_req, | 
 | 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP, | 
 | 				   req->base.complete, req->base.data); | 
 |  | 
 | 	ahash_request_set_crypt(&rctx->ahash_fbk_req, req->src, | 
 | 				req->result, req->nbytes); | 
 |  | 
 | 	return crypto_ahash_final(&rctx->ahash_fbk_req); | 
 | } | 
 |  | 
 | static int starfive_hash_finup(struct ahash_request *req) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 |  | 
 | 	ahash_request_set_tfm(&rctx->ahash_fbk_req, ctx->ahash_fbk); | 
 | 	ahash_request_set_callback(&rctx->ahash_fbk_req, | 
 | 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP, | 
 | 				   req->base.complete, req->base.data); | 
 |  | 
 | 	ahash_request_set_crypt(&rctx->ahash_fbk_req, req->src, | 
 | 				req->result, req->nbytes); | 
 |  | 
 | 	return crypto_ahash_finup(&rctx->ahash_fbk_req); | 
 | } | 
 |  | 
 | static int starfive_hash_digest(struct ahash_request *req) | 
 | { | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct starfive_cryp_dev *cryp = ctx->cryp; | 
 |  | 
 | 	memset(rctx, 0, sizeof(struct starfive_cryp_request_ctx)); | 
 |  | 
 | 	cryp->req.hreq = req; | 
 | 	rctx->total = req->nbytes; | 
 | 	rctx->in_sg = req->src; | 
 | 	rctx->blksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); | 
 | 	rctx->digsize = crypto_ahash_digestsize(tfm); | 
 | 	rctx->in_sg_len = sg_nents_for_len(rctx->in_sg, rctx->total); | 
 | 	ctx->rctx = rctx; | 
 |  | 
 | 	return crypto_transfer_hash_request_to_engine(cryp->engine, req); | 
 | } | 
 |  | 
 | static int starfive_hash_export(struct ahash_request *req, void *out) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 |  | 
 | 	ahash_request_set_tfm(&rctx->ahash_fbk_req, ctx->ahash_fbk); | 
 | 	ahash_request_set_callback(&rctx->ahash_fbk_req, | 
 | 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP, | 
 | 				   req->base.complete, req->base.data); | 
 |  | 
 | 	return crypto_ahash_export(&rctx->ahash_fbk_req, out); | 
 | } | 
 |  | 
 | static int starfive_hash_import(struct ahash_request *req, const void *in) | 
 | { | 
 | 	struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); | 
 | 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); | 
 |  | 
 | 	ahash_request_set_tfm(&rctx->ahash_fbk_req, ctx->ahash_fbk); | 
 | 	ahash_request_set_callback(&rctx->ahash_fbk_req, | 
 | 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP, | 
 | 				   req->base.complete, req->base.data); | 
 |  | 
 | 	return crypto_ahash_import(&rctx->ahash_fbk_req, in); | 
 | } | 
 |  | 
 | static int starfive_hash_init_tfm(struct crypto_ahash *hash, | 
 | 				  const char *alg_name, | 
 | 				  unsigned int mode, | 
 | 				  bool is_hmac) | 
 | { | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(hash); | 
 |  | 
 | 	ctx->cryp = starfive_cryp_find_dev(ctx); | 
 |  | 
 | 	if (!ctx->cryp) | 
 | 		return -ENODEV; | 
 |  | 
 | 	ctx->ahash_fbk = crypto_alloc_ahash(alg_name, 0, | 
 | 					    CRYPTO_ALG_NEED_FALLBACK); | 
 |  | 
 | 	if (IS_ERR(ctx->ahash_fbk)) | 
 | 		return dev_err_probe(ctx->cryp->dev, PTR_ERR(ctx->ahash_fbk), | 
 | 				     "starfive_hash: Could not load fallback driver.\n"); | 
 |  | 
 | 	crypto_ahash_set_statesize(hash, crypto_ahash_statesize(ctx->ahash_fbk)); | 
 | 	crypto_ahash_set_reqsize(hash, sizeof(struct starfive_cryp_request_ctx) + | 
 | 				 crypto_ahash_reqsize(ctx->ahash_fbk)); | 
 |  | 
 | 	ctx->is_hmac = is_hmac; | 
 | 	ctx->hash_mode = mode; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void starfive_hash_exit_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(hash); | 
 |  | 
 | 	crypto_free_ahash(ctx->ahash_fbk); | 
 | } | 
 |  | 
 | static int starfive_hash_long_setkey(struct starfive_cryp_ctx *ctx, | 
 | 				     const u8 *key, unsigned int keylen, | 
 | 				     const char *alg_name) | 
 | { | 
 | 	struct crypto_wait wait; | 
 | 	struct ahash_request *req; | 
 | 	struct scatterlist sg; | 
 | 	struct crypto_ahash *ahash_tfm; | 
 | 	u8 *buf; | 
 | 	int ret; | 
 |  | 
 | 	ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0); | 
 | 	if (IS_ERR(ahash_tfm)) | 
 | 		return PTR_ERR(ahash_tfm); | 
 |  | 
 | 	req = ahash_request_alloc(ahash_tfm, GFP_KERNEL); | 
 | 	if (!req) { | 
 | 		ret = -ENOMEM; | 
 | 		goto err_free_ahash; | 
 | 	} | 
 |  | 
 | 	crypto_init_wait(&wait); | 
 | 	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 
 | 				   crypto_req_done, &wait); | 
 | 	crypto_ahash_clear_flags(ahash_tfm, ~0); | 
 |  | 
 | 	buf = kzalloc(keylen + STARFIVE_HASH_BUFLEN, GFP_KERNEL); | 
 | 	if (!buf) { | 
 | 		ret = -ENOMEM; | 
 | 		goto err_free_req; | 
 | 	} | 
 |  | 
 | 	memcpy(buf, key, keylen); | 
 | 	sg_init_one(&sg, buf, keylen); | 
 | 	ahash_request_set_crypt(req, &sg, ctx->key, keylen); | 
 |  | 
 | 	ret = crypto_wait_req(crypto_ahash_digest(req), &wait); | 
 |  | 
 | 	kfree(buf); | 
 | err_free_req: | 
 | 	ahash_request_free(req); | 
 | err_free_ahash: | 
 | 	crypto_free_ahash(ahash_tfm); | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int starfive_hash_setkey(struct crypto_ahash *hash, | 
 | 				const u8 *key, unsigned int keylen) | 
 | { | 
 | 	struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(hash); | 
 | 	unsigned int digestsize = crypto_ahash_digestsize(hash); | 
 | 	unsigned int blocksize = crypto_ahash_blocksize(hash); | 
 | 	const char *alg_name; | 
 |  | 
 | 	crypto_ahash_setkey(ctx->ahash_fbk, key, keylen); | 
 |  | 
 | 	if (keylen <= blocksize) { | 
 | 		memcpy(ctx->key, key, keylen); | 
 | 		ctx->keylen = keylen; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	ctx->keylen = digestsize; | 
 |  | 
 | 	switch (digestsize) { | 
 | 	case SHA224_DIGEST_SIZE: | 
 | 		alg_name = "sha224-starfive"; | 
 | 		break; | 
 | 	case SHA256_DIGEST_SIZE: | 
 | 		if (ctx->hash_mode == STARFIVE_HASH_SM3) | 
 | 			alg_name = "sm3-starfive"; | 
 | 		else | 
 | 			alg_name = "sha256-starfive"; | 
 | 		break; | 
 | 	case SHA384_DIGEST_SIZE: | 
 | 		alg_name = "sha384-starfive"; | 
 | 		break; | 
 | 	case SHA512_DIGEST_SIZE: | 
 | 		alg_name = "sha512-starfive"; | 
 | 		break; | 
 | 	default: | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	return starfive_hash_long_setkey(ctx, key, keylen, alg_name); | 
 | } | 
 |  | 
 | static int starfive_sha224_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "sha224-lib", | 
 | 				      STARFIVE_HASH_SHA224, 0); | 
 | } | 
 |  | 
 | static int starfive_sha256_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "sha256-lib", | 
 | 				      STARFIVE_HASH_SHA256, 0); | 
 | } | 
 |  | 
 | static int starfive_sha384_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "sha384-lib", | 
 | 				      STARFIVE_HASH_SHA384, 0); | 
 | } | 
 |  | 
 | static int starfive_sha512_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "sha512-lib", | 
 | 				      STARFIVE_HASH_SHA512, 0); | 
 | } | 
 |  | 
 | static int starfive_sm3_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "sm3-generic", | 
 | 				      STARFIVE_HASH_SM3, 0); | 
 | } | 
 |  | 
 | static int starfive_hmac_sha224_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "hmac-sha224-lib", | 
 | 				      STARFIVE_HASH_SHA224, 1); | 
 | } | 
 |  | 
 | static int starfive_hmac_sha256_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "hmac-sha256-lib", | 
 | 				      STARFIVE_HASH_SHA256, 1); | 
 | } | 
 |  | 
 | static int starfive_hmac_sha384_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "hmac-sha384-lib", | 
 | 				      STARFIVE_HASH_SHA384, 1); | 
 | } | 
 |  | 
 | static int starfive_hmac_sha512_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "hmac-sha512-lib", | 
 | 				      STARFIVE_HASH_SHA512, 1); | 
 | } | 
 |  | 
 | static int starfive_hmac_sm3_init_tfm(struct crypto_ahash *hash) | 
 | { | 
 | 	return starfive_hash_init_tfm(hash, "hmac(sm3-generic)", | 
 | 				      STARFIVE_HASH_SM3, 1); | 
 | } | 
 |  | 
 | static struct ahash_engine_alg algs_sha2_sm3[] = { | 
 | { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_sha224_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA224_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha256_state), | 
 | 		.base = { | 
 | 			.cra_name		= "sha224", | 
 | 			.cra_driver_name	= "sha224-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA224_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_hmac_sha224_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.setkey   = starfive_hash_setkey, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA224_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha256_state), | 
 | 		.base = { | 
 | 			.cra_name		= "hmac(sha224)", | 
 | 			.cra_driver_name	= "sha224-hmac-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA224_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_sha256_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA256_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha256_state), | 
 | 		.base = { | 
 | 			.cra_name		= "sha256", | 
 | 			.cra_driver_name	= "sha256-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA256_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_hmac_sha256_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.setkey   = starfive_hash_setkey, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA256_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha256_state), | 
 | 		.base = { | 
 | 			.cra_name		= "hmac(sha256)", | 
 | 			.cra_driver_name	= "sha256-hmac-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA256_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_sha384_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA384_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha512_state), | 
 | 		.base = { | 
 | 			.cra_name		= "sha384", | 
 | 			.cra_driver_name	= "sha384-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA384_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_hmac_sha384_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.setkey   = starfive_hash_setkey, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA384_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha512_state), | 
 | 		.base = { | 
 | 			.cra_name		= "hmac(sha384)", | 
 | 			.cra_driver_name	= "sha384-hmac-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA384_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_sha512_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA512_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha512_state), | 
 | 		.base = { | 
 | 			.cra_name		= "sha512", | 
 | 			.cra_driver_name	= "sha512-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA512_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_hmac_sha512_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.setkey   = starfive_hash_setkey, | 
 | 	.base.halg = { | 
 | 		.digestsize = SHA512_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sha512_state), | 
 | 		.base = { | 
 | 			.cra_name		= "hmac(sha512)", | 
 | 			.cra_driver_name	= "sha512-hmac-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SHA512_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init     = starfive_hash_init, | 
 | 	.base.update   = starfive_hash_update, | 
 | 	.base.final    = starfive_hash_final, | 
 | 	.base.finup    = starfive_hash_finup, | 
 | 	.base.digest   = starfive_hash_digest, | 
 | 	.base.export   = starfive_hash_export, | 
 | 	.base.import   = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_sm3_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.halg = { | 
 | 		.digestsize = SM3_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sm3_state), | 
 | 		.base = { | 
 | 			.cra_name		= "sm3", | 
 | 			.cra_driver_name	= "sm3-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SM3_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, { | 
 | 	.base.init	  = starfive_hash_init, | 
 | 	.base.update	  = starfive_hash_update, | 
 | 	.base.final	  = starfive_hash_final, | 
 | 	.base.finup	  = starfive_hash_finup, | 
 | 	.base.digest	  = starfive_hash_digest, | 
 | 	.base.export	  = starfive_hash_export, | 
 | 	.base.import	  = starfive_hash_import, | 
 | 	.base.init_tfm = starfive_hmac_sm3_init_tfm, | 
 | 	.base.exit_tfm = starfive_hash_exit_tfm, | 
 | 	.base.setkey	  = starfive_hash_setkey, | 
 | 	.base.halg = { | 
 | 		.digestsize = SM3_DIGEST_SIZE, | 
 | 		.statesize  = sizeof(struct sm3_state), | 
 | 		.base = { | 
 | 			.cra_name		= "hmac(sm3)", | 
 | 			.cra_driver_name	= "sm3-hmac-starfive", | 
 | 			.cra_priority		= 200, | 
 | 			.cra_flags		= CRYPTO_ALG_ASYNC | | 
 | 						  CRYPTO_ALG_TYPE_AHASH | | 
 | 						  CRYPTO_ALG_NEED_FALLBACK, | 
 | 			.cra_blocksize		= SM3_BLOCK_SIZE, | 
 | 			.cra_ctxsize		= sizeof(struct starfive_cryp_ctx), | 
 | 			.cra_module		= THIS_MODULE, | 
 | 		} | 
 | 	}, | 
 | 	.op = { | 
 | 		.do_one_request = starfive_hash_one_request, | 
 | 	}, | 
 | }, | 
 | }; | 
 |  | 
 | int starfive_hash_register_algs(void) | 
 | { | 
 | 	return crypto_engine_register_ahashes(algs_sha2_sm3, ARRAY_SIZE(algs_sha2_sm3)); | 
 | } | 
 |  | 
 | void starfive_hash_unregister_algs(void) | 
 | { | 
 | 	crypto_engine_unregister_ahashes(algs_sha2_sm3, ARRAY_SIZE(algs_sha2_sm3)); | 
 | } |