162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
862306a36Sopenharmony_ci#include <linux/interrupt.h>
962306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "common.h"
1262306a36Sopenharmony_ci#include "core.h"
1362306a36Sopenharmony_ci#include "sha.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct qce_sha_saved_state {
1662306a36Sopenharmony_ci	u8 pending_buf[QCE_SHA_MAX_BLOCKSIZE];
1762306a36Sopenharmony_ci	u8 partial_digest[QCE_SHA_MAX_DIGESTSIZE];
1862306a36Sopenharmony_ci	__be32 byte_count[2];
1962306a36Sopenharmony_ci	unsigned int pending_buflen;
2062306a36Sopenharmony_ci	unsigned int flags;
2162306a36Sopenharmony_ci	u64 count;
2262306a36Sopenharmony_ci	bool first_blk;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic LIST_HEAD(ahash_algs);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = {
2862306a36Sopenharmony_ci	SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = {
3262306a36Sopenharmony_ci	SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
3362306a36Sopenharmony_ci	SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void qce_ahash_done(void *data)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct crypto_async_request *async_req = data;
3962306a36Sopenharmony_ci	struct ahash_request *req = ahash_request_cast(async_req);
4062306a36Sopenharmony_ci	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
4162306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
4262306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
4362306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
4462306a36Sopenharmony_ci	struct qce_result_dump *result = qce->dma.result_buf;
4562306a36Sopenharmony_ci	unsigned int digestsize = crypto_ahash_digestsize(ahash);
4662306a36Sopenharmony_ci	int error;
4762306a36Sopenharmony_ci	u32 status;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	error = qce_dma_terminate_all(&qce->dma);
5062306a36Sopenharmony_ci	if (error)
5162306a36Sopenharmony_ci		dev_dbg(qce->dev, "ahash dma termination error (%d)\n", error);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE);
5462306a36Sopenharmony_ci	dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	memcpy(rctx->digest, result->auth_iv, digestsize);
5762306a36Sopenharmony_ci	if (req->result && rctx->last_blk)
5862306a36Sopenharmony_ci		memcpy(req->result, result->auth_iv, digestsize);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]);
6162306a36Sopenharmony_ci	rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	error = qce_check_status(qce, &status);
6462306a36Sopenharmony_ci	if (error < 0)
6562306a36Sopenharmony_ci		dev_dbg(qce->dev, "ahash operation error (%x)\n", status);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	req->src = rctx->src_orig;
6862306a36Sopenharmony_ci	req->nbytes = rctx->nbytes_orig;
6962306a36Sopenharmony_ci	rctx->last_blk = false;
7062306a36Sopenharmony_ci	rctx->first_blk = false;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	qce->async_req_done(tmpl->qce, error);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct ahash_request *req = ahash_request_cast(async_req);
7862306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
7962306a36Sopenharmony_ci	struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
8062306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
8162306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
8262306a36Sopenharmony_ci	unsigned long flags = rctx->flags;
8362306a36Sopenharmony_ci	int ret;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (IS_SHA_HMAC(flags)) {
8662306a36Sopenharmony_ci		rctx->authkey = ctx->authkey;
8762306a36Sopenharmony_ci		rctx->authklen = QCE_SHA_HMAC_KEY_SIZE;
8862306a36Sopenharmony_ci	} else if (IS_CMAC(flags)) {
8962306a36Sopenharmony_ci		rctx->authkey = ctx->authkey;
9062306a36Sopenharmony_ci		rctx->authklen = AES_KEYSIZE_128;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	rctx->src_nents = sg_nents_for_len(req->src, req->nbytes);
9462306a36Sopenharmony_ci	if (rctx->src_nents < 0) {
9562306a36Sopenharmony_ci		dev_err(qce->dev, "Invalid numbers of src SG.\n");
9662306a36Sopenharmony_ci		return rctx->src_nents;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE);
10062306a36Sopenharmony_ci	if (!ret)
10162306a36Sopenharmony_ci		return -EIO;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ret = dma_map_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE);
10662306a36Sopenharmony_ci	if (!ret) {
10762306a36Sopenharmony_ci		ret = -EIO;
10862306a36Sopenharmony_ci		goto error_unmap_src;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	ret = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents,
11262306a36Sopenharmony_ci			       &rctx->result_sg, 1, qce_ahash_done, async_req);
11362306a36Sopenharmony_ci	if (ret)
11462306a36Sopenharmony_ci		goto error_unmap_dst;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	qce_dma_issue_pending(&qce->dma);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	ret = qce_start(async_req, tmpl->crypto_alg_type);
11962306a36Sopenharmony_ci	if (ret)
12062306a36Sopenharmony_ci		goto error_terminate;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cierror_terminate:
12562306a36Sopenharmony_ci	qce_dma_terminate_all(&qce->dma);
12662306a36Sopenharmony_cierror_unmap_dst:
12762306a36Sopenharmony_ci	dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE);
12862306a36Sopenharmony_cierror_unmap_src:
12962306a36Sopenharmony_ci	dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE);
13062306a36Sopenharmony_ci	return ret;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int qce_ahash_init(struct ahash_request *req)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
13662306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
13762306a36Sopenharmony_ci	const u32 *std_iv = tmpl->std_iv;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	memset(rctx, 0, sizeof(*rctx));
14062306a36Sopenharmony_ci	rctx->first_blk = true;
14162306a36Sopenharmony_ci	rctx->last_blk = false;
14262306a36Sopenharmony_ci	rctx->flags = tmpl->alg_flags;
14362306a36Sopenharmony_ci	memcpy(rctx->digest, std_iv, sizeof(rctx->digest));
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return 0;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int qce_ahash_export(struct ahash_request *req, void *out)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
15162306a36Sopenharmony_ci	struct qce_sha_saved_state *export_state = out;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	memcpy(export_state->pending_buf, rctx->buf, rctx->buflen);
15462306a36Sopenharmony_ci	memcpy(export_state->partial_digest, rctx->digest, sizeof(rctx->digest));
15562306a36Sopenharmony_ci	export_state->byte_count[0] = rctx->byte_count[0];
15662306a36Sopenharmony_ci	export_state->byte_count[1] = rctx->byte_count[1];
15762306a36Sopenharmony_ci	export_state->pending_buflen = rctx->buflen;
15862306a36Sopenharmony_ci	export_state->count = rctx->count;
15962306a36Sopenharmony_ci	export_state->first_blk = rctx->first_blk;
16062306a36Sopenharmony_ci	export_state->flags = rctx->flags;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int qce_ahash_import(struct ahash_request *req, const void *in)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
16862306a36Sopenharmony_ci	const struct qce_sha_saved_state *import_state = in;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	memset(rctx, 0, sizeof(*rctx));
17162306a36Sopenharmony_ci	rctx->count = import_state->count;
17262306a36Sopenharmony_ci	rctx->buflen = import_state->pending_buflen;
17362306a36Sopenharmony_ci	rctx->first_blk = import_state->first_blk;
17462306a36Sopenharmony_ci	rctx->flags = import_state->flags;
17562306a36Sopenharmony_ci	rctx->byte_count[0] = import_state->byte_count[0];
17662306a36Sopenharmony_ci	rctx->byte_count[1] = import_state->byte_count[1];
17762306a36Sopenharmony_ci	memcpy(rctx->buf, import_state->pending_buf, rctx->buflen);
17862306a36Sopenharmony_ci	memcpy(rctx->digest, import_state->partial_digest, sizeof(rctx->digest));
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int qce_ahash_update(struct ahash_request *req)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
18662306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
18762306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
18862306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
18962306a36Sopenharmony_ci	struct scatterlist *sg_last, *sg;
19062306a36Sopenharmony_ci	unsigned int total, len;
19162306a36Sopenharmony_ci	unsigned int hash_later;
19262306a36Sopenharmony_ci	unsigned int nbytes;
19362306a36Sopenharmony_ci	unsigned int blocksize;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
19662306a36Sopenharmony_ci	rctx->count += req->nbytes;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* check for buffer from previous updates and append it */
19962306a36Sopenharmony_ci	total = req->nbytes + rctx->buflen;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (total <= blocksize) {
20262306a36Sopenharmony_ci		scatterwalk_map_and_copy(rctx->buf + rctx->buflen, req->src,
20362306a36Sopenharmony_ci					 0, req->nbytes, 0);
20462306a36Sopenharmony_ci		rctx->buflen += req->nbytes;
20562306a36Sopenharmony_ci		return 0;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* save the original req structure fields */
20962306a36Sopenharmony_ci	rctx->src_orig = req->src;
21062306a36Sopenharmony_ci	rctx->nbytes_orig = req->nbytes;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * if we have data from previous update copy them on buffer. The old
21462306a36Sopenharmony_ci	 * data will be combined with current request bytes.
21562306a36Sopenharmony_ci	 */
21662306a36Sopenharmony_ci	if (rctx->buflen)
21762306a36Sopenharmony_ci		memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* calculate how many bytes will be hashed later */
22062306a36Sopenharmony_ci	hash_later = total % blocksize;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/*
22362306a36Sopenharmony_ci	 * At this point, there is more than one block size of data.  If
22462306a36Sopenharmony_ci	 * the available data to transfer is exactly a multiple of block
22562306a36Sopenharmony_ci	 * size, save the last block to be transferred in qce_ahash_final
22662306a36Sopenharmony_ci	 * (with the last block bit set) if this is indeed the end of data
22762306a36Sopenharmony_ci	 * stream. If not this saved block will be transferred as part of
22862306a36Sopenharmony_ci	 * next update. If this block is not held back and if this is
22962306a36Sopenharmony_ci	 * indeed the end of data stream, the digest obtained will be wrong
23062306a36Sopenharmony_ci	 * since qce_ahash_final will see that rctx->buflen is 0 and return
23162306a36Sopenharmony_ci	 * doing nothing which in turn means that a digest will not be
23262306a36Sopenharmony_ci	 * copied to the destination result buffer.  qce_ahash_final cannot
23362306a36Sopenharmony_ci	 * be made to alter this behavior and allowed to proceed if
23462306a36Sopenharmony_ci	 * rctx->buflen is 0 because the crypto engine BAM does not allow
23562306a36Sopenharmony_ci	 * for zero length transfers.
23662306a36Sopenharmony_ci	 */
23762306a36Sopenharmony_ci	if (!hash_later)
23862306a36Sopenharmony_ci		hash_later = blocksize;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (hash_later) {
24162306a36Sopenharmony_ci		unsigned int src_offset = req->nbytes - hash_later;
24262306a36Sopenharmony_ci		scatterwalk_map_and_copy(rctx->buf, req->src, src_offset,
24362306a36Sopenharmony_ci					 hash_later, 0);
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* here nbytes is multiple of blocksize */
24762306a36Sopenharmony_ci	nbytes = total - hash_later;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	len = rctx->buflen;
25062306a36Sopenharmony_ci	sg = sg_last = req->src;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	while (len < nbytes && sg) {
25362306a36Sopenharmony_ci		if (len + sg_dma_len(sg) > nbytes)
25462306a36Sopenharmony_ci			break;
25562306a36Sopenharmony_ci		len += sg_dma_len(sg);
25662306a36Sopenharmony_ci		sg_last = sg;
25762306a36Sopenharmony_ci		sg = sg_next(sg);
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (!sg_last)
26162306a36Sopenharmony_ci		return -EINVAL;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (rctx->buflen) {
26462306a36Sopenharmony_ci		sg_init_table(rctx->sg, 2);
26562306a36Sopenharmony_ci		sg_set_buf(rctx->sg, rctx->tmpbuf, rctx->buflen);
26662306a36Sopenharmony_ci		sg_chain(rctx->sg, 2, req->src);
26762306a36Sopenharmony_ci		req->src = rctx->sg;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	req->nbytes = nbytes;
27162306a36Sopenharmony_ci	rctx->buflen = hash_later;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return qce->async_req_enqueue(tmpl->qce, &req->base);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int qce_ahash_final(struct ahash_request *req)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
27962306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
28062306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (!rctx->buflen) {
28362306a36Sopenharmony_ci		if (tmpl->hash_zero)
28462306a36Sopenharmony_ci			memcpy(req->result, tmpl->hash_zero,
28562306a36Sopenharmony_ci					tmpl->alg.ahash.halg.digestsize);
28662306a36Sopenharmony_ci		return 0;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	rctx->last_blk = true;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	rctx->src_orig = req->src;
29262306a36Sopenharmony_ci	rctx->nbytes_orig = req->nbytes;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen);
29562306a36Sopenharmony_ci	sg_init_one(rctx->sg, rctx->tmpbuf, rctx->buflen);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	req->src = rctx->sg;
29862306a36Sopenharmony_ci	req->nbytes = rctx->buflen;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return qce->async_req_enqueue(tmpl->qce, &req->base);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic int qce_ahash_digest(struct ahash_request *req)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
30662306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
30762306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
30862306a36Sopenharmony_ci	int ret;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = qce_ahash_init(req);
31162306a36Sopenharmony_ci	if (ret)
31262306a36Sopenharmony_ci		return ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	rctx->src_orig = req->src;
31562306a36Sopenharmony_ci	rctx->nbytes_orig = req->nbytes;
31662306a36Sopenharmony_ci	rctx->first_blk = true;
31762306a36Sopenharmony_ci	rctx->last_blk = true;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (!rctx->nbytes_orig) {
32062306a36Sopenharmony_ci		if (tmpl->hash_zero)
32162306a36Sopenharmony_ci			memcpy(req->result, tmpl->hash_zero,
32262306a36Sopenharmony_ci					tmpl->alg.ahash.halg.digestsize);
32362306a36Sopenharmony_ci		return 0;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return qce->async_req_enqueue(tmpl->qce, &req->base);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic int qce_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
33062306a36Sopenharmony_ci				 unsigned int keylen)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	unsigned int digestsize = crypto_ahash_digestsize(tfm);
33362306a36Sopenharmony_ci	struct qce_sha_ctx *ctx = crypto_tfm_ctx(&tfm->base);
33462306a36Sopenharmony_ci	struct crypto_wait wait;
33562306a36Sopenharmony_ci	struct ahash_request *req;
33662306a36Sopenharmony_ci	struct scatterlist sg;
33762306a36Sopenharmony_ci	unsigned int blocksize;
33862306a36Sopenharmony_ci	struct crypto_ahash *ahash_tfm;
33962306a36Sopenharmony_ci	u8 *buf;
34062306a36Sopenharmony_ci	int ret;
34162306a36Sopenharmony_ci	const char *alg_name;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
34462306a36Sopenharmony_ci	memset(ctx->authkey, 0, sizeof(ctx->authkey));
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (keylen <= blocksize) {
34762306a36Sopenharmony_ci		memcpy(ctx->authkey, key, keylen);
34862306a36Sopenharmony_ci		return 0;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (digestsize == SHA1_DIGEST_SIZE)
35262306a36Sopenharmony_ci		alg_name = "sha1-qce";
35362306a36Sopenharmony_ci	else if (digestsize == SHA256_DIGEST_SIZE)
35462306a36Sopenharmony_ci		alg_name = "sha256-qce";
35562306a36Sopenharmony_ci	else
35662306a36Sopenharmony_ci		return -EINVAL;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0);
35962306a36Sopenharmony_ci	if (IS_ERR(ahash_tfm))
36062306a36Sopenharmony_ci		return PTR_ERR(ahash_tfm);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	req = ahash_request_alloc(ahash_tfm, GFP_KERNEL);
36362306a36Sopenharmony_ci	if (!req) {
36462306a36Sopenharmony_ci		ret = -ENOMEM;
36562306a36Sopenharmony_ci		goto err_free_ahash;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	crypto_init_wait(&wait);
36962306a36Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
37062306a36Sopenharmony_ci				   crypto_req_done, &wait);
37162306a36Sopenharmony_ci	crypto_ahash_clear_flags(ahash_tfm, ~0);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	buf = kzalloc(keylen + QCE_MAX_ALIGN_SIZE, GFP_KERNEL);
37462306a36Sopenharmony_ci	if (!buf) {
37562306a36Sopenharmony_ci		ret = -ENOMEM;
37662306a36Sopenharmony_ci		goto err_free_req;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	memcpy(buf, key, keylen);
38062306a36Sopenharmony_ci	sg_init_one(&sg, buf, keylen);
38162306a36Sopenharmony_ci	ahash_request_set_crypt(req, &sg, ctx->authkey, keylen);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	kfree(buf);
38662306a36Sopenharmony_cierr_free_req:
38762306a36Sopenharmony_ci	ahash_request_free(req);
38862306a36Sopenharmony_cierr_free_ahash:
38962306a36Sopenharmony_ci	crypto_free_ahash(ahash_tfm);
39062306a36Sopenharmony_ci	return ret;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int qce_ahash_cra_init(struct crypto_tfm *tfm)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
39662306a36Sopenharmony_ci	struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	crypto_ahash_set_reqsize_dma(ahash, sizeof(struct qce_sha_reqctx));
39962306a36Sopenharmony_ci	memset(ctx, 0, sizeof(*ctx));
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistruct qce_ahash_def {
40462306a36Sopenharmony_ci	unsigned long flags;
40562306a36Sopenharmony_ci	const char *name;
40662306a36Sopenharmony_ci	const char *drv_name;
40762306a36Sopenharmony_ci	unsigned int digestsize;
40862306a36Sopenharmony_ci	unsigned int blocksize;
40962306a36Sopenharmony_ci	unsigned int statesize;
41062306a36Sopenharmony_ci	const u32 *std_iv;
41162306a36Sopenharmony_ci};
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic const struct qce_ahash_def ahash_def[] = {
41462306a36Sopenharmony_ci	{
41562306a36Sopenharmony_ci		.flags		= QCE_HASH_SHA1,
41662306a36Sopenharmony_ci		.name		= "sha1",
41762306a36Sopenharmony_ci		.drv_name	= "sha1-qce",
41862306a36Sopenharmony_ci		.digestsize	= SHA1_DIGEST_SIZE,
41962306a36Sopenharmony_ci		.blocksize	= SHA1_BLOCK_SIZE,
42062306a36Sopenharmony_ci		.statesize	= sizeof(struct qce_sha_saved_state),
42162306a36Sopenharmony_ci		.std_iv		= std_iv_sha1,
42262306a36Sopenharmony_ci	},
42362306a36Sopenharmony_ci	{
42462306a36Sopenharmony_ci		.flags		= QCE_HASH_SHA256,
42562306a36Sopenharmony_ci		.name		= "sha256",
42662306a36Sopenharmony_ci		.drv_name	= "sha256-qce",
42762306a36Sopenharmony_ci		.digestsize	= SHA256_DIGEST_SIZE,
42862306a36Sopenharmony_ci		.blocksize	= SHA256_BLOCK_SIZE,
42962306a36Sopenharmony_ci		.statesize	= sizeof(struct qce_sha_saved_state),
43062306a36Sopenharmony_ci		.std_iv		= std_iv_sha256,
43162306a36Sopenharmony_ci	},
43262306a36Sopenharmony_ci	{
43362306a36Sopenharmony_ci		.flags		= QCE_HASH_SHA1_HMAC,
43462306a36Sopenharmony_ci		.name		= "hmac(sha1)",
43562306a36Sopenharmony_ci		.drv_name	= "hmac-sha1-qce",
43662306a36Sopenharmony_ci		.digestsize	= SHA1_DIGEST_SIZE,
43762306a36Sopenharmony_ci		.blocksize	= SHA1_BLOCK_SIZE,
43862306a36Sopenharmony_ci		.statesize	= sizeof(struct qce_sha_saved_state),
43962306a36Sopenharmony_ci		.std_iv		= std_iv_sha1,
44062306a36Sopenharmony_ci	},
44162306a36Sopenharmony_ci	{
44262306a36Sopenharmony_ci		.flags		= QCE_HASH_SHA256_HMAC,
44362306a36Sopenharmony_ci		.name		= "hmac(sha256)",
44462306a36Sopenharmony_ci		.drv_name	= "hmac-sha256-qce",
44562306a36Sopenharmony_ci		.digestsize	= SHA256_DIGEST_SIZE,
44662306a36Sopenharmony_ci		.blocksize	= SHA256_BLOCK_SIZE,
44762306a36Sopenharmony_ci		.statesize	= sizeof(struct qce_sha_saved_state),
44862306a36Sopenharmony_ci		.std_iv		= std_iv_sha256,
44962306a36Sopenharmony_ci	},
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic int qce_ahash_register_one(const struct qce_ahash_def *def,
45362306a36Sopenharmony_ci				  struct qce_device *qce)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct qce_alg_template *tmpl;
45662306a36Sopenharmony_ci	struct ahash_alg *alg;
45762306a36Sopenharmony_ci	struct crypto_alg *base;
45862306a36Sopenharmony_ci	int ret;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
46162306a36Sopenharmony_ci	if (!tmpl)
46262306a36Sopenharmony_ci		return -ENOMEM;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	tmpl->std_iv = def->std_iv;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	alg = &tmpl->alg.ahash;
46762306a36Sopenharmony_ci	alg->init = qce_ahash_init;
46862306a36Sopenharmony_ci	alg->update = qce_ahash_update;
46962306a36Sopenharmony_ci	alg->final = qce_ahash_final;
47062306a36Sopenharmony_ci	alg->digest = qce_ahash_digest;
47162306a36Sopenharmony_ci	alg->export = qce_ahash_export;
47262306a36Sopenharmony_ci	alg->import = qce_ahash_import;
47362306a36Sopenharmony_ci	if (IS_SHA_HMAC(def->flags))
47462306a36Sopenharmony_ci		alg->setkey = qce_ahash_hmac_setkey;
47562306a36Sopenharmony_ci	alg->halg.digestsize = def->digestsize;
47662306a36Sopenharmony_ci	alg->halg.statesize = def->statesize;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (IS_SHA1(def->flags))
47962306a36Sopenharmony_ci		tmpl->hash_zero = sha1_zero_message_hash;
48062306a36Sopenharmony_ci	else if (IS_SHA256(def->flags))
48162306a36Sopenharmony_ci		tmpl->hash_zero = sha256_zero_message_hash;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	base = &alg->halg.base;
48462306a36Sopenharmony_ci	base->cra_blocksize = def->blocksize;
48562306a36Sopenharmony_ci	base->cra_priority = 300;
48662306a36Sopenharmony_ci	base->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
48762306a36Sopenharmony_ci	base->cra_ctxsize = sizeof(struct qce_sha_ctx);
48862306a36Sopenharmony_ci	base->cra_alignmask = 0;
48962306a36Sopenharmony_ci	base->cra_module = THIS_MODULE;
49062306a36Sopenharmony_ci	base->cra_init = qce_ahash_cra_init;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
49362306a36Sopenharmony_ci	snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
49462306a36Sopenharmony_ci		 def->drv_name);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	INIT_LIST_HEAD(&tmpl->entry);
49762306a36Sopenharmony_ci	tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AHASH;
49862306a36Sopenharmony_ci	tmpl->alg_flags = def->flags;
49962306a36Sopenharmony_ci	tmpl->qce = qce;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	ret = crypto_register_ahash(alg);
50262306a36Sopenharmony_ci	if (ret) {
50362306a36Sopenharmony_ci		dev_err(qce->dev, "%s registration failed\n", base->cra_name);
50462306a36Sopenharmony_ci		kfree(tmpl);
50562306a36Sopenharmony_ci		return ret;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	list_add_tail(&tmpl->entry, &ahash_algs);
50962306a36Sopenharmony_ci	dev_dbg(qce->dev, "%s is registered\n", base->cra_name);
51062306a36Sopenharmony_ci	return 0;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic void qce_ahash_unregister(struct qce_device *qce)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct qce_alg_template *tmpl, *n;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	list_for_each_entry_safe(tmpl, n, &ahash_algs, entry) {
51862306a36Sopenharmony_ci		crypto_unregister_ahash(&tmpl->alg.ahash);
51962306a36Sopenharmony_ci		list_del(&tmpl->entry);
52062306a36Sopenharmony_ci		kfree(tmpl);
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic int qce_ahash_register(struct qce_device *qce)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	int ret, i;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ahash_def); i++) {
52962306a36Sopenharmony_ci		ret = qce_ahash_register_one(&ahash_def[i], qce);
53062306a36Sopenharmony_ci		if (ret)
53162306a36Sopenharmony_ci			goto err;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return 0;
53562306a36Sopenharmony_cierr:
53662306a36Sopenharmony_ci	qce_ahash_unregister(qce);
53762306a36Sopenharmony_ci	return ret;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ciconst struct qce_algo_ops ahash_ops = {
54162306a36Sopenharmony_ci	.type = CRYPTO_ALG_TYPE_AHASH,
54262306a36Sopenharmony_ci	.register_algs = qce_ahash_register,
54362306a36Sopenharmony_ci	.unregister_algs = qce_ahash_unregister,
54462306a36Sopenharmony_ci	.async_req_handle = qce_ahash_async_req_handle,
54562306a36Sopenharmony_ci};
546