18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/device.h>
78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
88c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
98c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "common.h"
128c2ecf20Sopenharmony_ci#include "core.h"
138c2ecf20Sopenharmony_ci#include "sha.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/* crypto hw padding constant for first operation */
168c2ecf20Sopenharmony_ci#define SHA_PADDING		64
178c2ecf20Sopenharmony_ci#define SHA_PADDING_MASK	(SHA_PADDING - 1)
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic LIST_HEAD(ahash_algs);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = {
228c2ecf20Sopenharmony_ci	SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = {
268c2ecf20Sopenharmony_ci	SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
278c2ecf20Sopenharmony_ci	SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void qce_ahash_done(void *data)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct crypto_async_request *async_req = data;
338c2ecf20Sopenharmony_ci	struct ahash_request *req = ahash_request_cast(async_req);
348c2ecf20Sopenharmony_ci	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
358c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
368c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
378c2ecf20Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
388c2ecf20Sopenharmony_ci	struct qce_result_dump *result = qce->dma.result_buf;
398c2ecf20Sopenharmony_ci	unsigned int digestsize = crypto_ahash_digestsize(ahash);
408c2ecf20Sopenharmony_ci	int error;
418c2ecf20Sopenharmony_ci	u32 status;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	error = qce_dma_terminate_all(&qce->dma);
448c2ecf20Sopenharmony_ci	if (error)
458c2ecf20Sopenharmony_ci		dev_dbg(qce->dev, "ahash dma termination error (%d)\n", error);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE);
488c2ecf20Sopenharmony_ci	dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	memcpy(rctx->digest, result->auth_iv, digestsize);
518c2ecf20Sopenharmony_ci	if (req->result)
528c2ecf20Sopenharmony_ci		memcpy(req->result, result->auth_iv, digestsize);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]);
558c2ecf20Sopenharmony_ci	rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	error = qce_check_status(qce, &status);
588c2ecf20Sopenharmony_ci	if (error < 0)
598c2ecf20Sopenharmony_ci		dev_dbg(qce->dev, "ahash operation error (%x)\n", status);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	req->src = rctx->src_orig;
628c2ecf20Sopenharmony_ci	req->nbytes = rctx->nbytes_orig;
638c2ecf20Sopenharmony_ci	rctx->last_blk = false;
648c2ecf20Sopenharmony_ci	rctx->first_blk = false;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	qce->async_req_done(tmpl->qce, error);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct ahash_request *req = ahash_request_cast(async_req);
728c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
738c2ecf20Sopenharmony_ci	struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
748c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
758c2ecf20Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
768c2ecf20Sopenharmony_ci	unsigned long flags = rctx->flags;
778c2ecf20Sopenharmony_ci	int ret;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (IS_SHA_HMAC(flags)) {
808c2ecf20Sopenharmony_ci		rctx->authkey = ctx->authkey;
818c2ecf20Sopenharmony_ci		rctx->authklen = QCE_SHA_HMAC_KEY_SIZE;
828c2ecf20Sopenharmony_ci	} else if (IS_CMAC(flags)) {
838c2ecf20Sopenharmony_ci		rctx->authkey = ctx->authkey;
848c2ecf20Sopenharmony_ci		rctx->authklen = AES_KEYSIZE_128;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	rctx->src_nents = sg_nents_for_len(req->src, req->nbytes);
888c2ecf20Sopenharmony_ci	if (rctx->src_nents < 0) {
898c2ecf20Sopenharmony_ci		dev_err(qce->dev, "Invalid numbers of src SG.\n");
908c2ecf20Sopenharmony_ci		return rctx->src_nents;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE);
948c2ecf20Sopenharmony_ci	if (ret < 0)
958c2ecf20Sopenharmony_ci		return ret;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	ret = dma_map_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE);
1008c2ecf20Sopenharmony_ci	if (ret < 0)
1018c2ecf20Sopenharmony_ci		goto error_unmap_src;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ret = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents,
1048c2ecf20Sopenharmony_ci			       &rctx->result_sg, 1, qce_ahash_done, async_req);
1058c2ecf20Sopenharmony_ci	if (ret)
1068c2ecf20Sopenharmony_ci		goto error_unmap_dst;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	qce_dma_issue_pending(&qce->dma);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	ret = qce_start(async_req, tmpl->crypto_alg_type, 0, 0);
1118c2ecf20Sopenharmony_ci	if (ret)
1128c2ecf20Sopenharmony_ci		goto error_terminate;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cierror_terminate:
1178c2ecf20Sopenharmony_ci	qce_dma_terminate_all(&qce->dma);
1188c2ecf20Sopenharmony_cierror_unmap_dst:
1198c2ecf20Sopenharmony_ci	dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE);
1208c2ecf20Sopenharmony_cierror_unmap_src:
1218c2ecf20Sopenharmony_ci	dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE);
1228c2ecf20Sopenharmony_ci	return ret;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int qce_ahash_init(struct ahash_request *req)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
1288c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
1298c2ecf20Sopenharmony_ci	const u32 *std_iv = tmpl->std_iv;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	memset(rctx, 0, sizeof(*rctx));
1328c2ecf20Sopenharmony_ci	rctx->first_blk = true;
1338c2ecf20Sopenharmony_ci	rctx->last_blk = false;
1348c2ecf20Sopenharmony_ci	rctx->flags = tmpl->alg_flags;
1358c2ecf20Sopenharmony_ci	memcpy(rctx->digest, std_iv, sizeof(rctx->digest));
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return 0;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int qce_ahash_export(struct ahash_request *req, void *out)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
1438c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
1448c2ecf20Sopenharmony_ci	unsigned long flags = rctx->flags;
1458c2ecf20Sopenharmony_ci	unsigned int digestsize = crypto_ahash_digestsize(ahash);
1468c2ecf20Sopenharmony_ci	unsigned int blocksize =
1478c2ecf20Sopenharmony_ci			crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash));
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
1508c2ecf20Sopenharmony_ci		struct sha1_state *out_state = out;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		out_state->count = rctx->count;
1538c2ecf20Sopenharmony_ci		qce_cpu_to_be32p_array((__be32 *)out_state->state,
1548c2ecf20Sopenharmony_ci				       rctx->digest, digestsize);
1558c2ecf20Sopenharmony_ci		memcpy(out_state->buffer, rctx->buf, blocksize);
1568c2ecf20Sopenharmony_ci	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) {
1578c2ecf20Sopenharmony_ci		struct sha256_state *out_state = out;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		out_state->count = rctx->count;
1608c2ecf20Sopenharmony_ci		qce_cpu_to_be32p_array((__be32 *)out_state->state,
1618c2ecf20Sopenharmony_ci				       rctx->digest, digestsize);
1628c2ecf20Sopenharmony_ci		memcpy(out_state->buf, rctx->buf, blocksize);
1638c2ecf20Sopenharmony_ci	} else {
1648c2ecf20Sopenharmony_ci		return -EINVAL;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return 0;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int qce_import_common(struct ahash_request *req, u64 in_count,
1718c2ecf20Sopenharmony_ci			     const u32 *state, const u8 *buffer, bool hmac)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
1748c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
1758c2ecf20Sopenharmony_ci	unsigned int digestsize = crypto_ahash_digestsize(ahash);
1768c2ecf20Sopenharmony_ci	unsigned int blocksize;
1778c2ecf20Sopenharmony_ci	u64 count = in_count;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash));
1808c2ecf20Sopenharmony_ci	rctx->count = in_count;
1818c2ecf20Sopenharmony_ci	memcpy(rctx->buf, buffer, blocksize);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (in_count <= blocksize) {
1848c2ecf20Sopenharmony_ci		rctx->first_blk = 1;
1858c2ecf20Sopenharmony_ci	} else {
1868c2ecf20Sopenharmony_ci		rctx->first_blk = 0;
1878c2ecf20Sopenharmony_ci		/*
1888c2ecf20Sopenharmony_ci		 * For HMAC, there is a hardware padding done when first block
1898c2ecf20Sopenharmony_ci		 * is set. Therefore the byte_count must be incremened by 64
1908c2ecf20Sopenharmony_ci		 * after the first block operation.
1918c2ecf20Sopenharmony_ci		 */
1928c2ecf20Sopenharmony_ci		if (hmac)
1938c2ecf20Sopenharmony_ci			count += SHA_PADDING;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	rctx->byte_count[0] = (__force __be32)(count & ~SHA_PADDING_MASK);
1978c2ecf20Sopenharmony_ci	rctx->byte_count[1] = (__force __be32)(count >> 32);
1988c2ecf20Sopenharmony_ci	qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state,
1998c2ecf20Sopenharmony_ci			       digestsize);
2008c2ecf20Sopenharmony_ci	rctx->buflen = (unsigned int)(in_count & (blocksize - 1));
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return 0;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int qce_ahash_import(struct ahash_request *req, const void *in)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx;
2088c2ecf20Sopenharmony_ci	unsigned long flags;
2098c2ecf20Sopenharmony_ci	bool hmac;
2108c2ecf20Sopenharmony_ci	int ret;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	ret = qce_ahash_init(req);
2138c2ecf20Sopenharmony_ci	if (ret)
2148c2ecf20Sopenharmony_ci		return ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	rctx = ahash_request_ctx(req);
2178c2ecf20Sopenharmony_ci	flags = rctx->flags;
2188c2ecf20Sopenharmony_ci	hmac = IS_SHA_HMAC(flags);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
2218c2ecf20Sopenharmony_ci		const struct sha1_state *state = in;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		ret = qce_import_common(req, state->count, state->state,
2248c2ecf20Sopenharmony_ci					state->buffer, hmac);
2258c2ecf20Sopenharmony_ci	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) {
2268c2ecf20Sopenharmony_ci		const struct sha256_state *state = in;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		ret = qce_import_common(req, state->count, state->state,
2298c2ecf20Sopenharmony_ci					state->buf, hmac);
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return ret;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int qce_ahash_update(struct ahash_request *req)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
2388c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
2398c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
2408c2ecf20Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
2418c2ecf20Sopenharmony_ci	struct scatterlist *sg_last, *sg;
2428c2ecf20Sopenharmony_ci	unsigned int total, len;
2438c2ecf20Sopenharmony_ci	unsigned int hash_later;
2448c2ecf20Sopenharmony_ci	unsigned int nbytes;
2458c2ecf20Sopenharmony_ci	unsigned int blocksize;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
2488c2ecf20Sopenharmony_ci	rctx->count += req->nbytes;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* check for buffer from previous updates and append it */
2518c2ecf20Sopenharmony_ci	total = req->nbytes + rctx->buflen;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (total <= blocksize) {
2548c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(rctx->buf + rctx->buflen, req->src,
2558c2ecf20Sopenharmony_ci					 0, req->nbytes, 0);
2568c2ecf20Sopenharmony_ci		rctx->buflen += req->nbytes;
2578c2ecf20Sopenharmony_ci		return 0;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* save the original req structure fields */
2618c2ecf20Sopenharmony_ci	rctx->src_orig = req->src;
2628c2ecf20Sopenharmony_ci	rctx->nbytes_orig = req->nbytes;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/*
2658c2ecf20Sopenharmony_ci	 * if we have data from previous update copy them on buffer. The old
2668c2ecf20Sopenharmony_ci	 * data will be combined with current request bytes.
2678c2ecf20Sopenharmony_ci	 */
2688c2ecf20Sopenharmony_ci	if (rctx->buflen)
2698c2ecf20Sopenharmony_ci		memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* calculate how many bytes will be hashed later */
2728c2ecf20Sopenharmony_ci	hash_later = total % blocksize;
2738c2ecf20Sopenharmony_ci	if (hash_later) {
2748c2ecf20Sopenharmony_ci		unsigned int src_offset = req->nbytes - hash_later;
2758c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(rctx->buf, req->src, src_offset,
2768c2ecf20Sopenharmony_ci					 hash_later, 0);
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* here nbytes is multiple of blocksize */
2808c2ecf20Sopenharmony_ci	nbytes = total - hash_later;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	len = rctx->buflen;
2838c2ecf20Sopenharmony_ci	sg = sg_last = req->src;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	while (len < nbytes && sg) {
2868c2ecf20Sopenharmony_ci		if (len + sg_dma_len(sg) > nbytes)
2878c2ecf20Sopenharmony_ci			break;
2888c2ecf20Sopenharmony_ci		len += sg_dma_len(sg);
2898c2ecf20Sopenharmony_ci		sg_last = sg;
2908c2ecf20Sopenharmony_ci		sg = sg_next(sg);
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (!sg_last)
2948c2ecf20Sopenharmony_ci		return -EINVAL;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (rctx->buflen) {
2978c2ecf20Sopenharmony_ci		sg_init_table(rctx->sg, 2);
2988c2ecf20Sopenharmony_ci		sg_set_buf(rctx->sg, rctx->tmpbuf, rctx->buflen);
2998c2ecf20Sopenharmony_ci		sg_chain(rctx->sg, 2, req->src);
3008c2ecf20Sopenharmony_ci		req->src = rctx->sg;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	req->nbytes = nbytes;
3048c2ecf20Sopenharmony_ci	rctx->buflen = hash_later;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return qce->async_req_enqueue(tmpl->qce, &req->base);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int qce_ahash_final(struct ahash_request *req)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
3128c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
3138c2ecf20Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (!rctx->buflen) {
3168c2ecf20Sopenharmony_ci		if (tmpl->hash_zero)
3178c2ecf20Sopenharmony_ci			memcpy(req->result, tmpl->hash_zero,
3188c2ecf20Sopenharmony_ci					tmpl->alg.ahash.halg.digestsize);
3198c2ecf20Sopenharmony_ci		return 0;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	rctx->last_blk = true;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	rctx->src_orig = req->src;
3258c2ecf20Sopenharmony_ci	rctx->nbytes_orig = req->nbytes;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen);
3288c2ecf20Sopenharmony_ci	sg_init_one(rctx->sg, rctx->tmpbuf, rctx->buflen);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	req->src = rctx->sg;
3318c2ecf20Sopenharmony_ci	req->nbytes = rctx->buflen;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return qce->async_req_enqueue(tmpl->qce, &req->base);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic int qce_ahash_digest(struct ahash_request *req)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
3398c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
3408c2ecf20Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
3418c2ecf20Sopenharmony_ci	int ret;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	ret = qce_ahash_init(req);
3448c2ecf20Sopenharmony_ci	if (ret)
3458c2ecf20Sopenharmony_ci		return ret;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	rctx->src_orig = req->src;
3488c2ecf20Sopenharmony_ci	rctx->nbytes_orig = req->nbytes;
3498c2ecf20Sopenharmony_ci	rctx->first_blk = true;
3508c2ecf20Sopenharmony_ci	rctx->last_blk = true;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (!rctx->nbytes_orig) {
3538c2ecf20Sopenharmony_ci		if (tmpl->hash_zero)
3548c2ecf20Sopenharmony_ci			memcpy(req->result, tmpl->hash_zero,
3558c2ecf20Sopenharmony_ci					tmpl->alg.ahash.halg.digestsize);
3568c2ecf20Sopenharmony_ci		return 0;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return qce->async_req_enqueue(tmpl->qce, &req->base);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int qce_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
3638c2ecf20Sopenharmony_ci				 unsigned int keylen)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	unsigned int digestsize = crypto_ahash_digestsize(tfm);
3668c2ecf20Sopenharmony_ci	struct qce_sha_ctx *ctx = crypto_tfm_ctx(&tfm->base);
3678c2ecf20Sopenharmony_ci	struct crypto_wait wait;
3688c2ecf20Sopenharmony_ci	struct ahash_request *req;
3698c2ecf20Sopenharmony_ci	struct scatterlist sg;
3708c2ecf20Sopenharmony_ci	unsigned int blocksize;
3718c2ecf20Sopenharmony_ci	struct crypto_ahash *ahash_tfm;
3728c2ecf20Sopenharmony_ci	u8 *buf;
3738c2ecf20Sopenharmony_ci	int ret;
3748c2ecf20Sopenharmony_ci	const char *alg_name;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
3778c2ecf20Sopenharmony_ci	memset(ctx->authkey, 0, sizeof(ctx->authkey));
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (keylen <= blocksize) {
3808c2ecf20Sopenharmony_ci		memcpy(ctx->authkey, key, keylen);
3818c2ecf20Sopenharmony_ci		return 0;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (digestsize == SHA1_DIGEST_SIZE)
3858c2ecf20Sopenharmony_ci		alg_name = "sha1-qce";
3868c2ecf20Sopenharmony_ci	else if (digestsize == SHA256_DIGEST_SIZE)
3878c2ecf20Sopenharmony_ci		alg_name = "sha256-qce";
3888c2ecf20Sopenharmony_ci	else
3898c2ecf20Sopenharmony_ci		return -EINVAL;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0);
3928c2ecf20Sopenharmony_ci	if (IS_ERR(ahash_tfm))
3938c2ecf20Sopenharmony_ci		return PTR_ERR(ahash_tfm);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	req = ahash_request_alloc(ahash_tfm, GFP_KERNEL);
3968c2ecf20Sopenharmony_ci	if (!req) {
3978c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3988c2ecf20Sopenharmony_ci		goto err_free_ahash;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	crypto_init_wait(&wait);
4028c2ecf20Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
4038c2ecf20Sopenharmony_ci				   crypto_req_done, &wait);
4048c2ecf20Sopenharmony_ci	crypto_ahash_clear_flags(ahash_tfm, ~0);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	buf = kzalloc(keylen + QCE_MAX_ALIGN_SIZE, GFP_KERNEL);
4078c2ecf20Sopenharmony_ci	if (!buf) {
4088c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4098c2ecf20Sopenharmony_ci		goto err_free_req;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	memcpy(buf, key, keylen);
4138c2ecf20Sopenharmony_ci	sg_init_one(&sg, buf, keylen);
4148c2ecf20Sopenharmony_ci	ahash_request_set_crypt(req, &sg, ctx->authkey, keylen);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	kfree(buf);
4198c2ecf20Sopenharmony_cierr_free_req:
4208c2ecf20Sopenharmony_ci	ahash_request_free(req);
4218c2ecf20Sopenharmony_cierr_free_ahash:
4228c2ecf20Sopenharmony_ci	crypto_free_ahash(ahash_tfm);
4238c2ecf20Sopenharmony_ci	return ret;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic int qce_ahash_cra_init(struct crypto_tfm *tfm)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
4298c2ecf20Sopenharmony_ci	struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	crypto_ahash_set_reqsize(ahash, sizeof(struct qce_sha_reqctx));
4328c2ecf20Sopenharmony_ci	memset(ctx, 0, sizeof(*ctx));
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistruct qce_ahash_def {
4378c2ecf20Sopenharmony_ci	unsigned long flags;
4388c2ecf20Sopenharmony_ci	const char *name;
4398c2ecf20Sopenharmony_ci	const char *drv_name;
4408c2ecf20Sopenharmony_ci	unsigned int digestsize;
4418c2ecf20Sopenharmony_ci	unsigned int blocksize;
4428c2ecf20Sopenharmony_ci	unsigned int statesize;
4438c2ecf20Sopenharmony_ci	const u32 *std_iv;
4448c2ecf20Sopenharmony_ci};
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic const struct qce_ahash_def ahash_def[] = {
4478c2ecf20Sopenharmony_ci	{
4488c2ecf20Sopenharmony_ci		.flags		= QCE_HASH_SHA1,
4498c2ecf20Sopenharmony_ci		.name		= "sha1",
4508c2ecf20Sopenharmony_ci		.drv_name	= "sha1-qce",
4518c2ecf20Sopenharmony_ci		.digestsize	= SHA1_DIGEST_SIZE,
4528c2ecf20Sopenharmony_ci		.blocksize	= SHA1_BLOCK_SIZE,
4538c2ecf20Sopenharmony_ci		.statesize	= sizeof(struct sha1_state),
4548c2ecf20Sopenharmony_ci		.std_iv		= std_iv_sha1,
4558c2ecf20Sopenharmony_ci	},
4568c2ecf20Sopenharmony_ci	{
4578c2ecf20Sopenharmony_ci		.flags		= QCE_HASH_SHA256,
4588c2ecf20Sopenharmony_ci		.name		= "sha256",
4598c2ecf20Sopenharmony_ci		.drv_name	= "sha256-qce",
4608c2ecf20Sopenharmony_ci		.digestsize	= SHA256_DIGEST_SIZE,
4618c2ecf20Sopenharmony_ci		.blocksize	= SHA256_BLOCK_SIZE,
4628c2ecf20Sopenharmony_ci		.statesize	= sizeof(struct sha256_state),
4638c2ecf20Sopenharmony_ci		.std_iv		= std_iv_sha256,
4648c2ecf20Sopenharmony_ci	},
4658c2ecf20Sopenharmony_ci	{
4668c2ecf20Sopenharmony_ci		.flags		= QCE_HASH_SHA1_HMAC,
4678c2ecf20Sopenharmony_ci		.name		= "hmac(sha1)",
4688c2ecf20Sopenharmony_ci		.drv_name	= "hmac-sha1-qce",
4698c2ecf20Sopenharmony_ci		.digestsize	= SHA1_DIGEST_SIZE,
4708c2ecf20Sopenharmony_ci		.blocksize	= SHA1_BLOCK_SIZE,
4718c2ecf20Sopenharmony_ci		.statesize	= sizeof(struct sha1_state),
4728c2ecf20Sopenharmony_ci		.std_iv		= std_iv_sha1,
4738c2ecf20Sopenharmony_ci	},
4748c2ecf20Sopenharmony_ci	{
4758c2ecf20Sopenharmony_ci		.flags		= QCE_HASH_SHA256_HMAC,
4768c2ecf20Sopenharmony_ci		.name		= "hmac(sha256)",
4778c2ecf20Sopenharmony_ci		.drv_name	= "hmac-sha256-qce",
4788c2ecf20Sopenharmony_ci		.digestsize	= SHA256_DIGEST_SIZE,
4798c2ecf20Sopenharmony_ci		.blocksize	= SHA256_BLOCK_SIZE,
4808c2ecf20Sopenharmony_ci		.statesize	= sizeof(struct sha256_state),
4818c2ecf20Sopenharmony_ci		.std_iv		= std_iv_sha256,
4828c2ecf20Sopenharmony_ci	},
4838c2ecf20Sopenharmony_ci};
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic int qce_ahash_register_one(const struct qce_ahash_def *def,
4868c2ecf20Sopenharmony_ci				  struct qce_device *qce)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl;
4898c2ecf20Sopenharmony_ci	struct ahash_alg *alg;
4908c2ecf20Sopenharmony_ci	struct crypto_alg *base;
4918c2ecf20Sopenharmony_ci	int ret;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
4948c2ecf20Sopenharmony_ci	if (!tmpl)
4958c2ecf20Sopenharmony_ci		return -ENOMEM;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	tmpl->std_iv = def->std_iv;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	alg = &tmpl->alg.ahash;
5008c2ecf20Sopenharmony_ci	alg->init = qce_ahash_init;
5018c2ecf20Sopenharmony_ci	alg->update = qce_ahash_update;
5028c2ecf20Sopenharmony_ci	alg->final = qce_ahash_final;
5038c2ecf20Sopenharmony_ci	alg->digest = qce_ahash_digest;
5048c2ecf20Sopenharmony_ci	alg->export = qce_ahash_export;
5058c2ecf20Sopenharmony_ci	alg->import = qce_ahash_import;
5068c2ecf20Sopenharmony_ci	if (IS_SHA_HMAC(def->flags))
5078c2ecf20Sopenharmony_ci		alg->setkey = qce_ahash_hmac_setkey;
5088c2ecf20Sopenharmony_ci	alg->halg.digestsize = def->digestsize;
5098c2ecf20Sopenharmony_ci	alg->halg.statesize = def->statesize;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (IS_SHA1(def->flags))
5128c2ecf20Sopenharmony_ci		tmpl->hash_zero = sha1_zero_message_hash;
5138c2ecf20Sopenharmony_ci	else if (IS_SHA256(def->flags))
5148c2ecf20Sopenharmony_ci		tmpl->hash_zero = sha256_zero_message_hash;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	base = &alg->halg.base;
5178c2ecf20Sopenharmony_ci	base->cra_blocksize = def->blocksize;
5188c2ecf20Sopenharmony_ci	base->cra_priority = 300;
5198c2ecf20Sopenharmony_ci	base->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
5208c2ecf20Sopenharmony_ci	base->cra_ctxsize = sizeof(struct qce_sha_ctx);
5218c2ecf20Sopenharmony_ci	base->cra_alignmask = 0;
5228c2ecf20Sopenharmony_ci	base->cra_module = THIS_MODULE;
5238c2ecf20Sopenharmony_ci	base->cra_init = qce_ahash_cra_init;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
5268c2ecf20Sopenharmony_ci	snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
5278c2ecf20Sopenharmony_ci		 def->drv_name);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tmpl->entry);
5308c2ecf20Sopenharmony_ci	tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AHASH;
5318c2ecf20Sopenharmony_ci	tmpl->alg_flags = def->flags;
5328c2ecf20Sopenharmony_ci	tmpl->qce = qce;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	ret = crypto_register_ahash(alg);
5358c2ecf20Sopenharmony_ci	if (ret) {
5368c2ecf20Sopenharmony_ci		dev_err(qce->dev, "%s registration failed\n", base->cra_name);
5378c2ecf20Sopenharmony_ci		kfree(tmpl);
5388c2ecf20Sopenharmony_ci		return ret;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	list_add_tail(&tmpl->entry, &ahash_algs);
5428c2ecf20Sopenharmony_ci	dev_dbg(qce->dev, "%s is registered\n", base->cra_name);
5438c2ecf20Sopenharmony_ci	return 0;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic void qce_ahash_unregister(struct qce_device *qce)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct qce_alg_template *tmpl, *n;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tmpl, n, &ahash_algs, entry) {
5518c2ecf20Sopenharmony_ci		crypto_unregister_ahash(&tmpl->alg.ahash);
5528c2ecf20Sopenharmony_ci		list_del(&tmpl->entry);
5538c2ecf20Sopenharmony_ci		kfree(tmpl);
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int qce_ahash_register(struct qce_device *qce)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	int ret, i;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ahash_def); i++) {
5628c2ecf20Sopenharmony_ci		ret = qce_ahash_register_one(&ahash_def[i], qce);
5638c2ecf20Sopenharmony_ci		if (ret)
5648c2ecf20Sopenharmony_ci			goto err;
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	return 0;
5688c2ecf20Sopenharmony_cierr:
5698c2ecf20Sopenharmony_ci	qce_ahash_unregister(qce);
5708c2ecf20Sopenharmony_ci	return ret;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ciconst struct qce_algo_ops ahash_ops = {
5748c2ecf20Sopenharmony_ci	.type = CRYPTO_ALG_TYPE_AHASH,
5758c2ecf20Sopenharmony_ci	.register_algs = qce_ahash_register,
5768c2ecf20Sopenharmony_ci	.unregister_algs = qce_ahash_unregister,
5778c2ecf20Sopenharmony_ci	.async_req_handle = qce_ahash_async_req_handle,
5788c2ecf20Sopenharmony_ci};
579