162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * sun8i-ce-cipher.c - hardware cryptographic offloader for
462306a36Sopenharmony_ci * Allwinner H3/A64/H5/H2+/H6/R40 SoC
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2016-2019 Corentin LABBE <clabbe.montjoie@gmail.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file add support for AES cipher with 128,192,256 bits keysize in
962306a36Sopenharmony_ci * CBC and ECB mode.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/bottom_half.h>
1562306a36Sopenharmony_ci#include <linux/crypto.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1962306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
2062306a36Sopenharmony_ci#include <crypto/internal/des.h>
2162306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
2262306a36Sopenharmony_ci#include "sun8i-ce.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int sun8i_ce_cipher_need_fallback(struct skcipher_request *areq)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
2762306a36Sopenharmony_ci	struct scatterlist *sg;
2862306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
2962306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
3062306a36Sopenharmony_ci	unsigned int todo, len;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (sg_nents_for_len(areq->src, areq->cryptlen) > MAX_SG ||
3562306a36Sopenharmony_ci	    sg_nents_for_len(areq->dst, areq->cryptlen) > MAX_SG) {
3662306a36Sopenharmony_ci		algt->stat_fb_maxsg++;
3762306a36Sopenharmony_ci		return true;
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (areq->cryptlen < crypto_skcipher_ivsize(tfm)) {
4162306a36Sopenharmony_ci		algt->stat_fb_leniv++;
4262306a36Sopenharmony_ci		return true;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (areq->cryptlen == 0) {
4662306a36Sopenharmony_ci		algt->stat_fb_len0++;
4762306a36Sopenharmony_ci		return true;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (areq->cryptlen % 16) {
5162306a36Sopenharmony_ci		algt->stat_fb_mod16++;
5262306a36Sopenharmony_ci		return true;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	len = areq->cryptlen;
5662306a36Sopenharmony_ci	sg = areq->src;
5762306a36Sopenharmony_ci	while (sg) {
5862306a36Sopenharmony_ci		if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
5962306a36Sopenharmony_ci			algt->stat_fb_srcali++;
6062306a36Sopenharmony_ci			return true;
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci		todo = min(len, sg->length);
6362306a36Sopenharmony_ci		if (todo % 4) {
6462306a36Sopenharmony_ci			algt->stat_fb_srclen++;
6562306a36Sopenharmony_ci			return true;
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci		len -= todo;
6862306a36Sopenharmony_ci		sg = sg_next(sg);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	len = areq->cryptlen;
7262306a36Sopenharmony_ci	sg = areq->dst;
7362306a36Sopenharmony_ci	while (sg) {
7462306a36Sopenharmony_ci		if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
7562306a36Sopenharmony_ci			algt->stat_fb_dstali++;
7662306a36Sopenharmony_ci			return true;
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci		todo = min(len, sg->length);
7962306a36Sopenharmony_ci		if (todo % 4) {
8062306a36Sopenharmony_ci			algt->stat_fb_dstlen++;
8162306a36Sopenharmony_ci			return true;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci		len -= todo;
8462306a36Sopenharmony_ci		sg = sg_next(sg);
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci	return false;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int sun8i_ce_cipher_fallback(struct skcipher_request *areq)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
9262306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
9362306a36Sopenharmony_ci	struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
9462306a36Sopenharmony_ci	int err;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
9762306a36Sopenharmony_ci		struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
9862306a36Sopenharmony_ci		struct sun8i_ce_alg_template *algt __maybe_unused;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		algt = container_of(alg, struct sun8i_ce_alg_template,
10162306a36Sopenharmony_ci				    alg.skcipher.base);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
10462306a36Sopenharmony_ci		algt->stat_fb++;
10562306a36Sopenharmony_ci#endif
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
10962306a36Sopenharmony_ci	skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
11062306a36Sopenharmony_ci				      areq->base.complete, areq->base.data);
11162306a36Sopenharmony_ci	skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
11262306a36Sopenharmony_ci				   areq->cryptlen, areq->iv);
11362306a36Sopenharmony_ci	if (rctx->op_dir & CE_DECRYPTION)
11462306a36Sopenharmony_ci		err = crypto_skcipher_decrypt(&rctx->fallback_req);
11562306a36Sopenharmony_ci	else
11662306a36Sopenharmony_ci		err = crypto_skcipher_encrypt(&rctx->fallback_req);
11762306a36Sopenharmony_ci	return err;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base);
12362306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
12462306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
12562306a36Sopenharmony_ci	struct sun8i_ce_dev *ce = op->ce;
12662306a36Sopenharmony_ci	struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
12762306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
12862306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
12962306a36Sopenharmony_ci	struct sun8i_ce_flow *chan;
13062306a36Sopenharmony_ci	struct ce_task *cet;
13162306a36Sopenharmony_ci	struct scatterlist *sg;
13262306a36Sopenharmony_ci	unsigned int todo, len, offset, ivsize;
13362306a36Sopenharmony_ci	u32 common, sym;
13462306a36Sopenharmony_ci	int flow, i;
13562306a36Sopenharmony_ci	int nr_sgs = 0;
13662306a36Sopenharmony_ci	int nr_sgd = 0;
13762306a36Sopenharmony_ci	int err = 0;
13862306a36Sopenharmony_ci	int ns = sg_nents_for_len(areq->src, areq->cryptlen);
13962306a36Sopenharmony_ci	int nd = sg_nents_for_len(areq->dst, areq->cryptlen);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
14462306a36Sopenharmony_ci		crypto_tfm_alg_name(areq->base.tfm),
14562306a36Sopenharmony_ci		areq->cryptlen,
14662306a36Sopenharmony_ci		rctx->op_dir, areq->iv, crypto_skcipher_ivsize(tfm),
14762306a36Sopenharmony_ci		op->keylen);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
15062306a36Sopenharmony_ci	algt->stat_req++;
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	flow = rctx->flow;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	chan = &ce->chanlist[flow];
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	cet = chan->tl;
15862306a36Sopenharmony_ci	memset(cet, 0, sizeof(struct ce_task));
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	cet->t_id = cpu_to_le32(flow);
16162306a36Sopenharmony_ci	common = ce->variant->alg_cipher[algt->ce_algo_id];
16262306a36Sopenharmony_ci	common |= rctx->op_dir | CE_COMM_INT;
16362306a36Sopenharmony_ci	cet->t_common_ctl = cpu_to_le32(common);
16462306a36Sopenharmony_ci	/* CTS and recent CE (H6) need length in bytes, in word otherwise */
16562306a36Sopenharmony_ci	if (ce->variant->cipher_t_dlen_in_bytes)
16662306a36Sopenharmony_ci		cet->t_dlen = cpu_to_le32(areq->cryptlen);
16762306a36Sopenharmony_ci	else
16862306a36Sopenharmony_ci		cet->t_dlen = cpu_to_le32(areq->cryptlen / 4);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	sym = ce->variant->op_mode[algt->ce_blockmode];
17162306a36Sopenharmony_ci	len = op->keylen;
17262306a36Sopenharmony_ci	switch (len) {
17362306a36Sopenharmony_ci	case 128 / 8:
17462306a36Sopenharmony_ci		sym |= CE_AES_128BITS;
17562306a36Sopenharmony_ci		break;
17662306a36Sopenharmony_ci	case 192 / 8:
17762306a36Sopenharmony_ci		sym |= CE_AES_192BITS;
17862306a36Sopenharmony_ci		break;
17962306a36Sopenharmony_ci	case 256 / 8:
18062306a36Sopenharmony_ci		sym |= CE_AES_256BITS;
18162306a36Sopenharmony_ci		break;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	cet->t_sym_ctl = cpu_to_le32(sym);
18562306a36Sopenharmony_ci	cet->t_asym_ctl = 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	rctx->addr_key = dma_map_single(ce->dev, op->key, op->keylen, DMA_TO_DEVICE);
18862306a36Sopenharmony_ci	if (dma_mapping_error(ce->dev, rctx->addr_key)) {
18962306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot DMA MAP KEY\n");
19062306a36Sopenharmony_ci		err = -EFAULT;
19162306a36Sopenharmony_ci		goto theend;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci	cet->t_key = cpu_to_le32(rctx->addr_key);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ivsize = crypto_skcipher_ivsize(tfm);
19662306a36Sopenharmony_ci	if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) {
19762306a36Sopenharmony_ci		rctx->ivlen = ivsize;
19862306a36Sopenharmony_ci		if (rctx->op_dir & CE_DECRYPTION) {
19962306a36Sopenharmony_ci			offset = areq->cryptlen - ivsize;
20062306a36Sopenharmony_ci			scatterwalk_map_and_copy(chan->backup_iv, areq->src,
20162306a36Sopenharmony_ci						 offset, ivsize, 0);
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci		memcpy(chan->bounce_iv, areq->iv, ivsize);
20462306a36Sopenharmony_ci		rctx->addr_iv = dma_map_single(ce->dev, chan->bounce_iv, rctx->ivlen,
20562306a36Sopenharmony_ci					       DMA_TO_DEVICE);
20662306a36Sopenharmony_ci		if (dma_mapping_error(ce->dev, rctx->addr_iv)) {
20762306a36Sopenharmony_ci			dev_err(ce->dev, "Cannot DMA MAP IV\n");
20862306a36Sopenharmony_ci			err = -ENOMEM;
20962306a36Sopenharmony_ci			goto theend_iv;
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci		cet->t_iv = cpu_to_le32(rctx->addr_iv);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (areq->src == areq->dst) {
21562306a36Sopenharmony_ci		nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_BIDIRECTIONAL);
21662306a36Sopenharmony_ci		if (nr_sgs <= 0 || nr_sgs > MAX_SG) {
21762306a36Sopenharmony_ci			dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
21862306a36Sopenharmony_ci			err = -EINVAL;
21962306a36Sopenharmony_ci			goto theend_iv;
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci		nr_sgd = nr_sgs;
22262306a36Sopenharmony_ci	} else {
22362306a36Sopenharmony_ci		nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
22462306a36Sopenharmony_ci		if (nr_sgs <= 0 || nr_sgs > MAX_SG) {
22562306a36Sopenharmony_ci			dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
22662306a36Sopenharmony_ci			err = -EINVAL;
22762306a36Sopenharmony_ci			goto theend_iv;
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci		nr_sgd = dma_map_sg(ce->dev, areq->dst, nd, DMA_FROM_DEVICE);
23062306a36Sopenharmony_ci		if (nr_sgd <= 0 || nr_sgd > MAX_SG) {
23162306a36Sopenharmony_ci			dev_err(ce->dev, "Invalid sg number %d\n", nr_sgd);
23262306a36Sopenharmony_ci			err = -EINVAL;
23362306a36Sopenharmony_ci			goto theend_sgs;
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	len = areq->cryptlen;
23862306a36Sopenharmony_ci	for_each_sg(areq->src, sg, nr_sgs, i) {
23962306a36Sopenharmony_ci		cet->t_src[i].addr = cpu_to_le32(sg_dma_address(sg));
24062306a36Sopenharmony_ci		todo = min(len, sg_dma_len(sg));
24162306a36Sopenharmony_ci		cet->t_src[i].len = cpu_to_le32(todo / 4);
24262306a36Sopenharmony_ci		dev_dbg(ce->dev, "%s total=%u SG(%d %u off=%d) todo=%u\n", __func__,
24362306a36Sopenharmony_ci			areq->cryptlen, i, cet->t_src[i].len, sg->offset, todo);
24462306a36Sopenharmony_ci		len -= todo;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci	if (len > 0) {
24762306a36Sopenharmony_ci		dev_err(ce->dev, "remaining len %d\n", len);
24862306a36Sopenharmony_ci		err = -EINVAL;
24962306a36Sopenharmony_ci		goto theend_sgs;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	len = areq->cryptlen;
25362306a36Sopenharmony_ci	for_each_sg(areq->dst, sg, nr_sgd, i) {
25462306a36Sopenharmony_ci		cet->t_dst[i].addr = cpu_to_le32(sg_dma_address(sg));
25562306a36Sopenharmony_ci		todo = min(len, sg_dma_len(sg));
25662306a36Sopenharmony_ci		cet->t_dst[i].len = cpu_to_le32(todo / 4);
25762306a36Sopenharmony_ci		dev_dbg(ce->dev, "%s total=%u SG(%d %u off=%d) todo=%u\n", __func__,
25862306a36Sopenharmony_ci			areq->cryptlen, i, cet->t_dst[i].len, sg->offset, todo);
25962306a36Sopenharmony_ci		len -= todo;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	if (len > 0) {
26262306a36Sopenharmony_ci		dev_err(ce->dev, "remaining len %d\n", len);
26362306a36Sopenharmony_ci		err = -EINVAL;
26462306a36Sopenharmony_ci		goto theend_sgs;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	chan->timeout = areq->cryptlen;
26862306a36Sopenharmony_ci	rctx->nr_sgs = nr_sgs;
26962306a36Sopenharmony_ci	rctx->nr_sgd = nr_sgd;
27062306a36Sopenharmony_ci	return 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_citheend_sgs:
27362306a36Sopenharmony_ci	if (areq->src == areq->dst) {
27462306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->src, ns, DMA_BIDIRECTIONAL);
27562306a36Sopenharmony_ci	} else {
27662306a36Sopenharmony_ci		if (nr_sgs > 0)
27762306a36Sopenharmony_ci			dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
27862306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->dst, nd, DMA_FROM_DEVICE);
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_citheend_iv:
28262306a36Sopenharmony_ci	if (areq->iv && ivsize > 0) {
28362306a36Sopenharmony_ci		if (rctx->addr_iv)
28462306a36Sopenharmony_ci			dma_unmap_single(ce->dev, rctx->addr_iv, rctx->ivlen, DMA_TO_DEVICE);
28562306a36Sopenharmony_ci		offset = areq->cryptlen - ivsize;
28662306a36Sopenharmony_ci		if (rctx->op_dir & CE_DECRYPTION) {
28762306a36Sopenharmony_ci			memcpy(areq->iv, chan->backup_iv, ivsize);
28862306a36Sopenharmony_ci			memzero_explicit(chan->backup_iv, ivsize);
28962306a36Sopenharmony_ci		} else {
29062306a36Sopenharmony_ci			scatterwalk_map_and_copy(areq->iv, areq->dst, offset,
29162306a36Sopenharmony_ci						 ivsize, 0);
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci		memzero_explicit(chan->bounce_iv, ivsize);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_citheend:
29962306a36Sopenharmony_ci	return err;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
30562306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq);
30662306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
30762306a36Sopenharmony_ci	struct sun8i_ce_dev *ce = op->ce;
30862306a36Sopenharmony_ci	struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq);
30962306a36Sopenharmony_ci	int flow, err;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	flow = rctx->flow;
31262306a36Sopenharmony_ci	err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm));
31362306a36Sopenharmony_ci	local_bh_disable();
31462306a36Sopenharmony_ci	crypto_finalize_skcipher_request(engine, breq, err);
31562306a36Sopenharmony_ci	local_bh_enable();
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void sun8i_ce_cipher_unprepare(struct crypto_engine *engine,
31962306a36Sopenharmony_ci				      void *async_req)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base);
32262306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
32362306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
32462306a36Sopenharmony_ci	struct sun8i_ce_dev *ce = op->ce;
32562306a36Sopenharmony_ci	struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
32662306a36Sopenharmony_ci	struct sun8i_ce_flow *chan;
32762306a36Sopenharmony_ci	struct ce_task *cet;
32862306a36Sopenharmony_ci	unsigned int ivsize, offset;
32962306a36Sopenharmony_ci	int nr_sgs = rctx->nr_sgs;
33062306a36Sopenharmony_ci	int nr_sgd = rctx->nr_sgd;
33162306a36Sopenharmony_ci	int flow;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	flow = rctx->flow;
33462306a36Sopenharmony_ci	chan = &ce->chanlist[flow];
33562306a36Sopenharmony_ci	cet = chan->tl;
33662306a36Sopenharmony_ci	ivsize = crypto_skcipher_ivsize(tfm);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (areq->src == areq->dst) {
33962306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL);
34062306a36Sopenharmony_ci	} else {
34162306a36Sopenharmony_ci		if (nr_sgs > 0)
34262306a36Sopenharmony_ci			dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_TO_DEVICE);
34362306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE);
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (areq->iv && ivsize > 0) {
34762306a36Sopenharmony_ci		if (cet->t_iv)
34862306a36Sopenharmony_ci			dma_unmap_single(ce->dev, rctx->addr_iv, rctx->ivlen, DMA_TO_DEVICE);
34962306a36Sopenharmony_ci		offset = areq->cryptlen - ivsize;
35062306a36Sopenharmony_ci		if (rctx->op_dir & CE_DECRYPTION) {
35162306a36Sopenharmony_ci			memcpy(areq->iv, chan->backup_iv, ivsize);
35262306a36Sopenharmony_ci			memzero_explicit(chan->backup_iv, ivsize);
35362306a36Sopenharmony_ci		} else {
35462306a36Sopenharmony_ci			scatterwalk_map_and_copy(areq->iv, areq->dst, offset,
35562306a36Sopenharmony_ci						 ivsize, 0);
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		memzero_explicit(chan->bounce_iv, ivsize);
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ciint sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	int err = sun8i_ce_cipher_prepare(engine, areq);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (err)
36862306a36Sopenharmony_ci		return err;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	sun8i_ce_cipher_run(engine, areq);
37162306a36Sopenharmony_ci	sun8i_ce_cipher_unprepare(engine, areq);
37262306a36Sopenharmony_ci	return 0;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ciint sun8i_ce_skdecrypt(struct skcipher_request *areq)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
37862306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
37962306a36Sopenharmony_ci	struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
38062306a36Sopenharmony_ci	struct crypto_engine *engine;
38162306a36Sopenharmony_ci	int e;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	rctx->op_dir = CE_DECRYPTION;
38462306a36Sopenharmony_ci	if (sun8i_ce_cipher_need_fallback(areq))
38562306a36Sopenharmony_ci		return sun8i_ce_cipher_fallback(areq);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	e = sun8i_ce_get_engine_number(op->ce);
38862306a36Sopenharmony_ci	rctx->flow = e;
38962306a36Sopenharmony_ci	engine = op->ce->chanlist[e].engine;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return crypto_transfer_skcipher_request_to_engine(engine, areq);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ciint sun8i_ce_skencrypt(struct skcipher_request *areq)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
39762306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
39862306a36Sopenharmony_ci	struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
39962306a36Sopenharmony_ci	struct crypto_engine *engine;
40062306a36Sopenharmony_ci	int e;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	rctx->op_dir = CE_ENCRYPTION;
40362306a36Sopenharmony_ci	if (sun8i_ce_cipher_need_fallback(areq))
40462306a36Sopenharmony_ci		return sun8i_ce_cipher_fallback(areq);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	e = sun8i_ce_get_engine_number(op->ce);
40762306a36Sopenharmony_ci	rctx->flow = e;
40862306a36Sopenharmony_ci	engine = op->ce->chanlist[e].engine;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return crypto_transfer_skcipher_request_to_engine(engine, areq);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ciint sun8i_ce_cipher_init(struct crypto_tfm *tfm)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
41662306a36Sopenharmony_ci	struct sun8i_ce_alg_template *algt;
41762306a36Sopenharmony_ci	const char *name = crypto_tfm_alg_name(tfm);
41862306a36Sopenharmony_ci	struct crypto_skcipher *sktfm = __crypto_skcipher_cast(tfm);
41962306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(sktfm);
42062306a36Sopenharmony_ci	int err;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	memset(op, 0, sizeof(struct sun8i_cipher_tfm_ctx));
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base);
42562306a36Sopenharmony_ci	op->ce = algt->ce;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
42862306a36Sopenharmony_ci	if (IS_ERR(op->fallback_tfm)) {
42962306a36Sopenharmony_ci		dev_err(op->ce->dev, "ERROR: Cannot allocate fallback for %s %ld\n",
43062306a36Sopenharmony_ci			name, PTR_ERR(op->fallback_tfm));
43162306a36Sopenharmony_ci		return PTR_ERR(op->fallback_tfm);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	sktfm->reqsize = sizeof(struct sun8i_cipher_req_ctx) +
43562306a36Sopenharmony_ci			 crypto_skcipher_reqsize(op->fallback_tfm);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	memcpy(algt->fbname,
43862306a36Sopenharmony_ci	       crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)),
43962306a36Sopenharmony_ci	       CRYPTO_MAX_ALG_NAME);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	err = pm_runtime_get_sync(op->ce->dev);
44262306a36Sopenharmony_ci	if (err < 0)
44362306a36Sopenharmony_ci		goto error_pm;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_cierror_pm:
44762306a36Sopenharmony_ci	pm_runtime_put_noidle(op->ce->dev);
44862306a36Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
44962306a36Sopenharmony_ci	return err;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_civoid sun8i_ce_cipher_exit(struct crypto_tfm *tfm)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	kfree_sensitive(op->key);
45762306a36Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
45862306a36Sopenharmony_ci	pm_runtime_put_sync_suspend(op->ce->dev);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ciint sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
46262306a36Sopenharmony_ci			unsigned int keylen)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
46562306a36Sopenharmony_ci	struct sun8i_ce_dev *ce = op->ce;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	switch (keylen) {
46862306a36Sopenharmony_ci	case 128 / 8:
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	case 192 / 8:
47162306a36Sopenharmony_ci		break;
47262306a36Sopenharmony_ci	case 256 / 8:
47362306a36Sopenharmony_ci		break;
47462306a36Sopenharmony_ci	default:
47562306a36Sopenharmony_ci		dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
47662306a36Sopenharmony_ci		return -EINVAL;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci	kfree_sensitive(op->key);
47962306a36Sopenharmony_ci	op->keylen = keylen;
48062306a36Sopenharmony_ci	op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
48162306a36Sopenharmony_ci	if (!op->key)
48262306a36Sopenharmony_ci		return -ENOMEM;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
48562306a36Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ciint sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
49162306a36Sopenharmony_ci			 unsigned int keylen)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
49462306a36Sopenharmony_ci	int err;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	err = verify_skcipher_des3_key(tfm, key);
49762306a36Sopenharmony_ci	if (err)
49862306a36Sopenharmony_ci		return err;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	kfree_sensitive(op->key);
50162306a36Sopenharmony_ci	op->keylen = keylen;
50262306a36Sopenharmony_ci	op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
50362306a36Sopenharmony_ci	if (!op->key)
50462306a36Sopenharmony_ci		return -ENOMEM;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
50762306a36Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
51062306a36Sopenharmony_ci}
511