162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * sun8i-ce-hash.c - hardware cryptographic offloader for
462306a36Sopenharmony_ci * Allwinner H3/A64/H5/H2+/H6/R40 SoC
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file add support for MD5 and SHA1/SHA224/SHA256/SHA384/SHA512.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * You could find the datasheet in Documentation/arch/arm/sunxi.rst
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1462306a36Sopenharmony_ci#include <crypto/md5.h>
1562306a36Sopenharmony_ci#include <crypto/sha1.h>
1662306a36Sopenharmony_ci#include <crypto/sha2.h>
1762306a36Sopenharmony_ci#include <linux/bottom_half.h>
1862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2162306a36Sopenharmony_ci#include <linux/scatterlist.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/string.h>
2462306a36Sopenharmony_ci#include "sun8i-ce.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint sun8i_ce_hash_init_tfm(struct crypto_ahash *tfm)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *op = crypto_ahash_ctx(tfm);
2962306a36Sopenharmony_ci	struct ahash_alg *alg = crypto_ahash_alg(tfm);
3062306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
3162306a36Sopenharmony_ci	int err;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
3462306a36Sopenharmony_ci	op->ce = algt->ce;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	/* FALLBACK */
3762306a36Sopenharmony_ci	op->fallback_tfm = crypto_alloc_ahash(crypto_ahash_alg_name(tfm), 0,
3862306a36Sopenharmony_ci					      CRYPTO_ALG_NEED_FALLBACK);
3962306a36Sopenharmony_ci	if (IS_ERR(op->fallback_tfm)) {
4062306a36Sopenharmony_ci		dev_err(algt->ce->dev, "Fallback driver could no be loaded\n");
4162306a36Sopenharmony_ci		return PTR_ERR(op->fallback_tfm);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	crypto_ahash_set_statesize(tfm,
4562306a36Sopenharmony_ci				   crypto_ahash_statesize(op->fallback_tfm));
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	crypto_ahash_set_reqsize(tfm,
4862306a36Sopenharmony_ci				 sizeof(struct sun8i_ce_hash_reqctx) +
4962306a36Sopenharmony_ci				 crypto_ahash_reqsize(op->fallback_tfm));
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	memcpy(algt->fbname, crypto_ahash_driver_name(op->fallback_tfm),
5262306a36Sopenharmony_ci	       CRYPTO_MAX_ALG_NAME);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	err = pm_runtime_get_sync(op->ce->dev);
5562306a36Sopenharmony_ci	if (err < 0)
5662306a36Sopenharmony_ci		goto error_pm;
5762306a36Sopenharmony_ci	return 0;
5862306a36Sopenharmony_cierror_pm:
5962306a36Sopenharmony_ci	pm_runtime_put_noidle(op->ce->dev);
6062306a36Sopenharmony_ci	crypto_free_ahash(op->fallback_tfm);
6162306a36Sopenharmony_ci	return err;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_civoid sun8i_ce_hash_exit_tfm(struct crypto_ahash *tfm)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	crypto_free_ahash(tfmctx->fallback_tfm);
6962306a36Sopenharmony_ci	pm_runtime_put_sync_suspend(tfmctx->ce->dev);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciint sun8i_ce_hash_init(struct ahash_request *areq)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
7562306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
7662306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	memset(rctx, 0, sizeof(struct sun8i_ce_hash_reqctx));
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
8162306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return crypto_ahash_init(&rctx->fallback_req);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciint sun8i_ce_hash_export(struct ahash_request *areq, void *out)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
8962306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
9062306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
9362306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return crypto_ahash_export(&rctx->fallback_req, out);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciint sun8i_ce_hash_import(struct ahash_request *areq, const void *in)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
10162306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
10262306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
10562306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return crypto_ahash_import(&rctx->fallback_req, in);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciint sun8i_ce_hash_final(struct ahash_request *areq)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
11362306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
11462306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
11762306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags &
11862306a36Sopenharmony_ci					CRYPTO_TFM_REQ_MAY_SLEEP;
11962306a36Sopenharmony_ci	rctx->fallback_req.result = areq->result;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
12262306a36Sopenharmony_ci		struct sun8i_ce_alg_template *algt __maybe_unused;
12362306a36Sopenharmony_ci		struct ahash_alg *alg = crypto_ahash_alg(tfm);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		algt = container_of(alg, struct sun8i_ce_alg_template,
12662306a36Sopenharmony_ci				    alg.hash.base);
12762306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
12862306a36Sopenharmony_ci		algt->stat_fb++;
12962306a36Sopenharmony_ci#endif
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return crypto_ahash_final(&rctx->fallback_req);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciint sun8i_ce_hash_update(struct ahash_request *areq)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
13862306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
13962306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
14262306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags &
14362306a36Sopenharmony_ci					CRYPTO_TFM_REQ_MAY_SLEEP;
14462306a36Sopenharmony_ci	rctx->fallback_req.nbytes = areq->nbytes;
14562306a36Sopenharmony_ci	rctx->fallback_req.src = areq->src;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return crypto_ahash_update(&rctx->fallback_req);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciint sun8i_ce_hash_finup(struct ahash_request *areq)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
15362306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
15462306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
15762306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags &
15862306a36Sopenharmony_ci					CRYPTO_TFM_REQ_MAY_SLEEP;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	rctx->fallback_req.nbytes = areq->nbytes;
16162306a36Sopenharmony_ci	rctx->fallback_req.src = areq->src;
16262306a36Sopenharmony_ci	rctx->fallback_req.result = areq->result;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
16562306a36Sopenharmony_ci		struct sun8i_ce_alg_template *algt __maybe_unused;
16662306a36Sopenharmony_ci		struct ahash_alg *alg = crypto_ahash_alg(tfm);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		algt = container_of(alg, struct sun8i_ce_alg_template,
16962306a36Sopenharmony_ci				    alg.hash.base);
17062306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
17162306a36Sopenharmony_ci		algt->stat_fb++;
17262306a36Sopenharmony_ci#endif
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return crypto_ahash_finup(&rctx->fallback_req);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic int sun8i_ce_hash_digest_fb(struct ahash_request *areq)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
18162306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
18262306a36Sopenharmony_ci	struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
18562306a36Sopenharmony_ci	rctx->fallback_req.base.flags = areq->base.flags &
18662306a36Sopenharmony_ci					CRYPTO_TFM_REQ_MAY_SLEEP;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	rctx->fallback_req.nbytes = areq->nbytes;
18962306a36Sopenharmony_ci	rctx->fallback_req.src = areq->src;
19062306a36Sopenharmony_ci	rctx->fallback_req.result = areq->result;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
19362306a36Sopenharmony_ci		struct sun8i_ce_alg_template *algt __maybe_unused;
19462306a36Sopenharmony_ci		struct ahash_alg *alg = crypto_ahash_alg(tfm);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		algt = container_of(alg, struct sun8i_ce_alg_template,
19762306a36Sopenharmony_ci				    alg.hash.base);
19862306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
19962306a36Sopenharmony_ci		algt->stat_fb++;
20062306a36Sopenharmony_ci#endif
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return crypto_ahash_digest(&rctx->fallback_req);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic bool sun8i_ce_hash_need_fallback(struct ahash_request *areq)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
20962306a36Sopenharmony_ci	struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
21062306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
21162306a36Sopenharmony_ci	struct scatterlist *sg;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (areq->nbytes == 0) {
21662306a36Sopenharmony_ci		algt->stat_fb_len0++;
21762306a36Sopenharmony_ci		return true;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci	/* we need to reserve one SG for padding one */
22062306a36Sopenharmony_ci	if (sg_nents_for_len(areq->src, areq->nbytes) > MAX_SG - 1) {
22162306a36Sopenharmony_ci		algt->stat_fb_maxsg++;
22262306a36Sopenharmony_ci		return true;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci	sg = areq->src;
22562306a36Sopenharmony_ci	while (sg) {
22662306a36Sopenharmony_ci		if (sg->length % 4) {
22762306a36Sopenharmony_ci			algt->stat_fb_srclen++;
22862306a36Sopenharmony_ci			return true;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci		if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
23162306a36Sopenharmony_ci			algt->stat_fb_srcali++;
23262306a36Sopenharmony_ci			return true;
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci		sg = sg_next(sg);
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci	return false;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciint sun8i_ce_hash_digest(struct ahash_request *areq)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
24262306a36Sopenharmony_ci	struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
24362306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
24462306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
24562306a36Sopenharmony_ci	struct sun8i_ce_dev *ce;
24662306a36Sopenharmony_ci	struct crypto_engine *engine;
24762306a36Sopenharmony_ci	struct scatterlist *sg;
24862306a36Sopenharmony_ci	int nr_sgs, e, i;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (sun8i_ce_hash_need_fallback(areq))
25162306a36Sopenharmony_ci		return sun8i_ce_hash_digest_fb(areq);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	nr_sgs = sg_nents_for_len(areq->src, areq->nbytes);
25462306a36Sopenharmony_ci	if (nr_sgs > MAX_SG - 1)
25562306a36Sopenharmony_ci		return sun8i_ce_hash_digest_fb(areq);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	for_each_sg(areq->src, sg, nr_sgs, i) {
25862306a36Sopenharmony_ci		if (sg->length % 4 || !IS_ALIGNED(sg->offset, sizeof(u32)))
25962306a36Sopenharmony_ci			return sun8i_ce_hash_digest_fb(areq);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
26362306a36Sopenharmony_ci	ce = algt->ce;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	e = sun8i_ce_get_engine_number(ce);
26662306a36Sopenharmony_ci	rctx->flow = e;
26762306a36Sopenharmony_ci	engine = ce->chanlist[e].engine;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return crypto_transfer_hash_request_to_engine(engine, areq);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic u64 hash_pad(__le32 *buf, unsigned int bufsize, u64 padi, u64 byte_count, bool le, int bs)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	u64 fill, min_fill, j, k;
27562306a36Sopenharmony_ci	__be64 *bebits;
27662306a36Sopenharmony_ci	__le64 *lebits;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	j = padi;
27962306a36Sopenharmony_ci	buf[j++] = cpu_to_le32(0x80);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (bs == 64) {
28262306a36Sopenharmony_ci		fill = 64 - (byte_count % 64);
28362306a36Sopenharmony_ci		min_fill = 2 * sizeof(u32) + sizeof(u32);
28462306a36Sopenharmony_ci	} else {
28562306a36Sopenharmony_ci		fill = 128 - (byte_count % 128);
28662306a36Sopenharmony_ci		min_fill = 4 * sizeof(u32) + sizeof(u32);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (fill < min_fill)
29062306a36Sopenharmony_ci		fill += bs;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	k = j;
29362306a36Sopenharmony_ci	j += (fill - min_fill) / sizeof(u32);
29462306a36Sopenharmony_ci	if (j * 4 > bufsize) {
29562306a36Sopenharmony_ci		pr_err("%s OVERFLOW %llu\n", __func__, j);
29662306a36Sopenharmony_ci		return 0;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	for (; k < j; k++)
29962306a36Sopenharmony_ci		buf[k] = 0;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (le) {
30262306a36Sopenharmony_ci		/* MD5 */
30362306a36Sopenharmony_ci		lebits = (__le64 *)&buf[j];
30462306a36Sopenharmony_ci		*lebits = cpu_to_le64(byte_count << 3);
30562306a36Sopenharmony_ci		j += 2;
30662306a36Sopenharmony_ci	} else {
30762306a36Sopenharmony_ci		if (bs == 64) {
30862306a36Sopenharmony_ci			/* sha1 sha224 sha256 */
30962306a36Sopenharmony_ci			bebits = (__be64 *)&buf[j];
31062306a36Sopenharmony_ci			*bebits = cpu_to_be64(byte_count << 3);
31162306a36Sopenharmony_ci			j += 2;
31262306a36Sopenharmony_ci		} else {
31362306a36Sopenharmony_ci			/* sha384 sha512*/
31462306a36Sopenharmony_ci			bebits = (__be64 *)&buf[j];
31562306a36Sopenharmony_ci			*bebits = cpu_to_be64(byte_count >> 61);
31662306a36Sopenharmony_ci			j += 2;
31762306a36Sopenharmony_ci			bebits = (__be64 *)&buf[j];
31862306a36Sopenharmony_ci			*bebits = cpu_to_be64(byte_count << 3);
31962306a36Sopenharmony_ci			j += 2;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci	if (j * 4 > bufsize) {
32362306a36Sopenharmony_ci		pr_err("%s OVERFLOW %llu\n", __func__, j);
32462306a36Sopenharmony_ci		return 0;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return j;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciint sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct ahash_request *areq = container_of(breq, struct ahash_request, base);
33362306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
33462306a36Sopenharmony_ci	struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
33562306a36Sopenharmony_ci	struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
33662306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
33762306a36Sopenharmony_ci	struct sun8i_ce_dev *ce;
33862306a36Sopenharmony_ci	struct sun8i_ce_flow *chan;
33962306a36Sopenharmony_ci	struct ce_task *cet;
34062306a36Sopenharmony_ci	struct scatterlist *sg;
34162306a36Sopenharmony_ci	int nr_sgs, flow, err;
34262306a36Sopenharmony_ci	unsigned int len;
34362306a36Sopenharmony_ci	u32 common;
34462306a36Sopenharmony_ci	u64 byte_count;
34562306a36Sopenharmony_ci	__le32 *bf;
34662306a36Sopenharmony_ci	void *buf = NULL;
34762306a36Sopenharmony_ci	int j, i, todo;
34862306a36Sopenharmony_ci	void *result = NULL;
34962306a36Sopenharmony_ci	u64 bs;
35062306a36Sopenharmony_ci	int digestsize;
35162306a36Sopenharmony_ci	dma_addr_t addr_res, addr_pad;
35262306a36Sopenharmony_ci	int ns = sg_nents_for_len(areq->src, areq->nbytes);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
35562306a36Sopenharmony_ci	ce = algt->ce;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	bs = algt->alg.hash.base.halg.base.cra_blocksize;
35862306a36Sopenharmony_ci	digestsize = algt->alg.hash.base.halg.digestsize;
35962306a36Sopenharmony_ci	if (digestsize == SHA224_DIGEST_SIZE)
36062306a36Sopenharmony_ci		digestsize = SHA256_DIGEST_SIZE;
36162306a36Sopenharmony_ci	if (digestsize == SHA384_DIGEST_SIZE)
36262306a36Sopenharmony_ci		digestsize = SHA512_DIGEST_SIZE;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* the padding could be up to two block. */
36562306a36Sopenharmony_ci	buf = kzalloc(bs * 2, GFP_KERNEL | GFP_DMA);
36662306a36Sopenharmony_ci	if (!buf) {
36762306a36Sopenharmony_ci		err = -ENOMEM;
36862306a36Sopenharmony_ci		goto theend;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci	bf = (__le32 *)buf;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA);
37362306a36Sopenharmony_ci	if (!result) {
37462306a36Sopenharmony_ci		err = -ENOMEM;
37562306a36Sopenharmony_ci		goto theend;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	flow = rctx->flow;
37962306a36Sopenharmony_ci	chan = &ce->chanlist[flow];
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
38262306a36Sopenharmony_ci	algt->stat_req++;
38362306a36Sopenharmony_ci#endif
38462306a36Sopenharmony_ci	dev_dbg(ce->dev, "%s %s len=%d\n", __func__, crypto_tfm_alg_name(areq->base.tfm), areq->nbytes);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	cet = chan->tl;
38762306a36Sopenharmony_ci	memset(cet, 0, sizeof(struct ce_task));
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	cet->t_id = cpu_to_le32(flow);
39062306a36Sopenharmony_ci	common = ce->variant->alg_hash[algt->ce_algo_id];
39162306a36Sopenharmony_ci	common |= CE_COMM_INT;
39262306a36Sopenharmony_ci	cet->t_common_ctl = cpu_to_le32(common);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	cet->t_sym_ctl = 0;
39562306a36Sopenharmony_ci	cet->t_asym_ctl = 0;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
39862306a36Sopenharmony_ci	if (nr_sgs <= 0 || nr_sgs > MAX_SG) {
39962306a36Sopenharmony_ci		dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
40062306a36Sopenharmony_ci		err = -EINVAL;
40162306a36Sopenharmony_ci		goto theend;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	len = areq->nbytes;
40562306a36Sopenharmony_ci	for_each_sg(areq->src, sg, nr_sgs, i) {
40662306a36Sopenharmony_ci		cet->t_src[i].addr = cpu_to_le32(sg_dma_address(sg));
40762306a36Sopenharmony_ci		todo = min(len, sg_dma_len(sg));
40862306a36Sopenharmony_ci		cet->t_src[i].len = cpu_to_le32(todo / 4);
40962306a36Sopenharmony_ci		len -= todo;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	if (len > 0) {
41262306a36Sopenharmony_ci		dev_err(ce->dev, "remaining len %d\n", len);
41362306a36Sopenharmony_ci		err = -EINVAL;
41462306a36Sopenharmony_ci		goto theend;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci	addr_res = dma_map_single(ce->dev, result, digestsize, DMA_FROM_DEVICE);
41762306a36Sopenharmony_ci	cet->t_dst[0].addr = cpu_to_le32(addr_res);
41862306a36Sopenharmony_ci	cet->t_dst[0].len = cpu_to_le32(digestsize / 4);
41962306a36Sopenharmony_ci	if (dma_mapping_error(ce->dev, addr_res)) {
42062306a36Sopenharmony_ci		dev_err(ce->dev, "DMA map dest\n");
42162306a36Sopenharmony_ci		err = -EINVAL;
42262306a36Sopenharmony_ci		goto theend;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	byte_count = areq->nbytes;
42662306a36Sopenharmony_ci	j = 0;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	switch (algt->ce_algo_id) {
42962306a36Sopenharmony_ci	case CE_ID_HASH_MD5:
43062306a36Sopenharmony_ci		j = hash_pad(bf, 2 * bs, j, byte_count, true, bs);
43162306a36Sopenharmony_ci		break;
43262306a36Sopenharmony_ci	case CE_ID_HASH_SHA1:
43362306a36Sopenharmony_ci	case CE_ID_HASH_SHA224:
43462306a36Sopenharmony_ci	case CE_ID_HASH_SHA256:
43562306a36Sopenharmony_ci		j = hash_pad(bf, 2 * bs, j, byte_count, false, bs);
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci	case CE_ID_HASH_SHA384:
43862306a36Sopenharmony_ci	case CE_ID_HASH_SHA512:
43962306a36Sopenharmony_ci		j = hash_pad(bf, 2 * bs, j, byte_count, false, bs);
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	if (!j) {
44362306a36Sopenharmony_ci		err = -EINVAL;
44462306a36Sopenharmony_ci		goto theend;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	addr_pad = dma_map_single(ce->dev, buf, j * 4, DMA_TO_DEVICE);
44862306a36Sopenharmony_ci	cet->t_src[i].addr = cpu_to_le32(addr_pad);
44962306a36Sopenharmony_ci	cet->t_src[i].len = cpu_to_le32(j);
45062306a36Sopenharmony_ci	if (dma_mapping_error(ce->dev, addr_pad)) {
45162306a36Sopenharmony_ci		dev_err(ce->dev, "DMA error on padding SG\n");
45262306a36Sopenharmony_ci		err = -EINVAL;
45362306a36Sopenharmony_ci		goto theend;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (ce->variant->hash_t_dlen_in_bits)
45762306a36Sopenharmony_ci		cet->t_dlen = cpu_to_le32((areq->nbytes + j * 4) * 8);
45862306a36Sopenharmony_ci	else
45962306a36Sopenharmony_ci		cet->t_dlen = cpu_to_le32(areq->nbytes / 4 + j);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	chan->timeout = areq->nbytes;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm));
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE);
46662306a36Sopenharmony_ci	dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
46762306a36Sopenharmony_ci	dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	memcpy(areq->result, result, algt->alg.hash.base.halg.digestsize);
47162306a36Sopenharmony_citheend:
47262306a36Sopenharmony_ci	kfree(buf);
47362306a36Sopenharmony_ci	kfree(result);
47462306a36Sopenharmony_ci	local_bh_disable();
47562306a36Sopenharmony_ci	crypto_finalize_hash_request(engine, breq, err);
47662306a36Sopenharmony_ci	local_bh_enable();
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
479