162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * sl3516-ce-cipher.c - hardware cryptographic offloader for Storlink SL3516 SoC
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Corentin LABBE <clabbe@baylibre.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file adds support for AES cipher with 128,192,256 bits keysize in
862306a36Sopenharmony_ci * ECB mode.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <crypto/engine.h>
1262306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1362306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
1462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/string.h>
2262306a36Sopenharmony_ci#include "sl3516-ce.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* sl3516_ce_need_fallback - check if a request can be handled by the CE */
2562306a36Sopenharmony_cistatic bool sl3516_ce_need_fallback(struct skcipher_request *areq)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
2862306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
2962306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = op->ce;
3062306a36Sopenharmony_ci	struct scatterlist *in_sg;
3162306a36Sopenharmony_ci	struct scatterlist *out_sg;
3262306a36Sopenharmony_ci	struct scatterlist *sg;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (areq->cryptlen == 0 || areq->cryptlen % 16) {
3562306a36Sopenharmony_ci		ce->fallback_mod16++;
3662306a36Sopenharmony_ci		return true;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/*
4062306a36Sopenharmony_ci	 * check if we have enough descriptors for TX
4162306a36Sopenharmony_ci	 * Note: TX need one control desc for each SG
4262306a36Sopenharmony_ci	 */
4362306a36Sopenharmony_ci	if (sg_nents(areq->src) > MAXDESC / 2) {
4462306a36Sopenharmony_ci		ce->fallback_sg_count_tx++;
4562306a36Sopenharmony_ci		return true;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci	/* check if we have enough descriptors for RX */
4862306a36Sopenharmony_ci	if (sg_nents(areq->dst) > MAXDESC) {
4962306a36Sopenharmony_ci		ce->fallback_sg_count_rx++;
5062306a36Sopenharmony_ci		return true;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	sg = areq->src;
5462306a36Sopenharmony_ci	while (sg) {
5562306a36Sopenharmony_ci		if ((sg->length % 16) != 0) {
5662306a36Sopenharmony_ci			ce->fallback_mod16++;
5762306a36Sopenharmony_ci			return true;
5862306a36Sopenharmony_ci		}
5962306a36Sopenharmony_ci		if ((sg_dma_len(sg) % 16) != 0) {
6062306a36Sopenharmony_ci			ce->fallback_mod16++;
6162306a36Sopenharmony_ci			return true;
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci		if (!IS_ALIGNED(sg->offset, 16)) {
6462306a36Sopenharmony_ci			ce->fallback_align16++;
6562306a36Sopenharmony_ci			return true;
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci		sg = sg_next(sg);
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	sg = areq->dst;
7062306a36Sopenharmony_ci	while (sg) {
7162306a36Sopenharmony_ci		if ((sg->length % 16) != 0) {
7262306a36Sopenharmony_ci			ce->fallback_mod16++;
7362306a36Sopenharmony_ci			return true;
7462306a36Sopenharmony_ci		}
7562306a36Sopenharmony_ci		if ((sg_dma_len(sg) % 16) != 0) {
7662306a36Sopenharmony_ci			ce->fallback_mod16++;
7762306a36Sopenharmony_ci			return true;
7862306a36Sopenharmony_ci		}
7962306a36Sopenharmony_ci		if (!IS_ALIGNED(sg->offset, 16)) {
8062306a36Sopenharmony_ci			ce->fallback_align16++;
8162306a36Sopenharmony_ci			return true;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci		sg = sg_next(sg);
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* need same numbers of SG (with same length) for source and destination */
8762306a36Sopenharmony_ci	in_sg = areq->src;
8862306a36Sopenharmony_ci	out_sg = areq->dst;
8962306a36Sopenharmony_ci	while (in_sg && out_sg) {
9062306a36Sopenharmony_ci		if (in_sg->length != out_sg->length) {
9162306a36Sopenharmony_ci			ce->fallback_not_same_len++;
9262306a36Sopenharmony_ci			return true;
9362306a36Sopenharmony_ci		}
9462306a36Sopenharmony_ci		in_sg = sg_next(in_sg);
9562306a36Sopenharmony_ci		out_sg = sg_next(out_sg);
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	if (in_sg || out_sg)
9862306a36Sopenharmony_ci		return true;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return false;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int sl3516_ce_cipher_fallback(struct skcipher_request *areq)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
10662306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
10762306a36Sopenharmony_ci	struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
10862306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
10962306a36Sopenharmony_ci	struct sl3516_ce_alg_template *algt;
11062306a36Sopenharmony_ci	int err;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher.base);
11362306a36Sopenharmony_ci	algt->stat_fb++;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
11662306a36Sopenharmony_ci	skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
11762306a36Sopenharmony_ci				      areq->base.complete, areq->base.data);
11862306a36Sopenharmony_ci	skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
11962306a36Sopenharmony_ci				   areq->cryptlen, areq->iv);
12062306a36Sopenharmony_ci	if (rctx->op_dir == CE_DECRYPTION)
12162306a36Sopenharmony_ci		err = crypto_skcipher_decrypt(&rctx->fallback_req);
12262306a36Sopenharmony_ci	else
12362306a36Sopenharmony_ci		err = crypto_skcipher_encrypt(&rctx->fallback_req);
12462306a36Sopenharmony_ci	return err;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int sl3516_ce_cipher(struct skcipher_request *areq)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
13062306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
13162306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = op->ce;
13262306a36Sopenharmony_ci	struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
13362306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
13462306a36Sopenharmony_ci	struct sl3516_ce_alg_template *algt;
13562306a36Sopenharmony_ci	struct scatterlist *sg;
13662306a36Sopenharmony_ci	unsigned int todo, len;
13762306a36Sopenharmony_ci	struct pkt_control_ecb *ecb;
13862306a36Sopenharmony_ci	int nr_sgs = 0;
13962306a36Sopenharmony_ci	int nr_sgd = 0;
14062306a36Sopenharmony_ci	int err = 0;
14162306a36Sopenharmony_ci	int i;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher.base);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
14662306a36Sopenharmony_ci		crypto_tfm_alg_name(areq->base.tfm),
14762306a36Sopenharmony_ci		areq->cryptlen,
14862306a36Sopenharmony_ci		rctx->op_dir, areq->iv, crypto_skcipher_ivsize(tfm),
14962306a36Sopenharmony_ci		op->keylen);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	algt->stat_req++;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (areq->src == areq->dst) {
15462306a36Sopenharmony_ci		nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src),
15562306a36Sopenharmony_ci				    DMA_BIDIRECTIONAL);
15662306a36Sopenharmony_ci		if (nr_sgs <= 0 || nr_sgs > MAXDESC / 2) {
15762306a36Sopenharmony_ci			dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
15862306a36Sopenharmony_ci			err = -EINVAL;
15962306a36Sopenharmony_ci			goto theend;
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci		nr_sgd = nr_sgs;
16262306a36Sopenharmony_ci	} else {
16362306a36Sopenharmony_ci		nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src),
16462306a36Sopenharmony_ci				    DMA_TO_DEVICE);
16562306a36Sopenharmony_ci		if (nr_sgs <= 0 || nr_sgs > MAXDESC / 2) {
16662306a36Sopenharmony_ci			dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
16762306a36Sopenharmony_ci			err = -EINVAL;
16862306a36Sopenharmony_ci			goto theend;
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci		nr_sgd = dma_map_sg(ce->dev, areq->dst, sg_nents(areq->dst),
17162306a36Sopenharmony_ci				    DMA_FROM_DEVICE);
17262306a36Sopenharmony_ci		if (nr_sgd <= 0 || nr_sgd > MAXDESC) {
17362306a36Sopenharmony_ci			dev_err(ce->dev, "Invalid sg number %d\n", nr_sgd);
17462306a36Sopenharmony_ci			err = -EINVAL;
17562306a36Sopenharmony_ci			goto theend_sgs;
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	len = areq->cryptlen;
18062306a36Sopenharmony_ci	i = 0;
18162306a36Sopenharmony_ci	sg = areq->src;
18262306a36Sopenharmony_ci	while (i < nr_sgs && sg && len) {
18362306a36Sopenharmony_ci		if (sg_dma_len(sg) == 0)
18462306a36Sopenharmony_ci			goto sgs_next;
18562306a36Sopenharmony_ci		rctx->t_src[i].addr = sg_dma_address(sg);
18662306a36Sopenharmony_ci		todo = min(len, sg_dma_len(sg));
18762306a36Sopenharmony_ci		rctx->t_src[i].len = todo;
18862306a36Sopenharmony_ci		dev_dbg(ce->dev, "%s total=%u SGS(%d %u off=%d) todo=%u\n", __func__,
18962306a36Sopenharmony_ci			areq->cryptlen, i, rctx->t_src[i].len, sg->offset, todo);
19062306a36Sopenharmony_ci		len -= todo;
19162306a36Sopenharmony_ci		i++;
19262306a36Sopenharmony_cisgs_next:
19362306a36Sopenharmony_ci		sg = sg_next(sg);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	if (len > 0) {
19662306a36Sopenharmony_ci		dev_err(ce->dev, "remaining len %d/%u nr_sgs=%d\n", len, areq->cryptlen, nr_sgs);
19762306a36Sopenharmony_ci		err = -EINVAL;
19862306a36Sopenharmony_ci		goto theend_sgs;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	len = areq->cryptlen;
20262306a36Sopenharmony_ci	i = 0;
20362306a36Sopenharmony_ci	sg = areq->dst;
20462306a36Sopenharmony_ci	while (i < nr_sgd && sg && len) {
20562306a36Sopenharmony_ci		if (sg_dma_len(sg) == 0)
20662306a36Sopenharmony_ci			goto sgd_next;
20762306a36Sopenharmony_ci		rctx->t_dst[i].addr = sg_dma_address(sg);
20862306a36Sopenharmony_ci		todo = min(len, sg_dma_len(sg));
20962306a36Sopenharmony_ci		rctx->t_dst[i].len = todo;
21062306a36Sopenharmony_ci		dev_dbg(ce->dev, "%s total=%u SGD(%d %u off=%d) todo=%u\n", __func__,
21162306a36Sopenharmony_ci			areq->cryptlen, i, rctx->t_dst[i].len, sg->offset, todo);
21262306a36Sopenharmony_ci		len -= todo;
21362306a36Sopenharmony_ci		i++;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cisgd_next:
21662306a36Sopenharmony_ci		sg = sg_next(sg);
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci	if (len > 0) {
21962306a36Sopenharmony_ci		dev_err(ce->dev, "remaining len %d\n", len);
22062306a36Sopenharmony_ci		err = -EINVAL;
22162306a36Sopenharmony_ci		goto theend_sgs;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	switch (algt->mode) {
22562306a36Sopenharmony_ci	case ECB_AES:
22662306a36Sopenharmony_ci		rctx->pctrllen = sizeof(struct pkt_control_ecb);
22762306a36Sopenharmony_ci		ecb = (struct pkt_control_ecb *)ce->pctrl;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		rctx->tqflag = TQ0_TYPE_CTRL;
23062306a36Sopenharmony_ci		rctx->tqflag |= TQ1_CIPHER;
23162306a36Sopenharmony_ci		ecb->control.op_mode = rctx->op_dir;
23262306a36Sopenharmony_ci		ecb->control.cipher_algorithm = ECB_AES;
23362306a36Sopenharmony_ci		ecb->cipher.header_len = 0;
23462306a36Sopenharmony_ci		ecb->cipher.algorithm_len = areq->cryptlen;
23562306a36Sopenharmony_ci		cpu_to_be32_array((__be32 *)ecb->key, (u32 *)op->key, op->keylen / 4);
23662306a36Sopenharmony_ci		rctx->h = &ecb->cipher;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		rctx->tqflag |= TQ4_KEY0;
23962306a36Sopenharmony_ci		rctx->tqflag |= TQ5_KEY4;
24062306a36Sopenharmony_ci		rctx->tqflag |= TQ6_KEY6;
24162306a36Sopenharmony_ci		ecb->control.aesnk = op->keylen / 4;
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	rctx->nr_sgs = nr_sgs;
24662306a36Sopenharmony_ci	rctx->nr_sgd = nr_sgd;
24762306a36Sopenharmony_ci	err = sl3516_ce_run_task(ce, rctx, crypto_tfm_alg_name(areq->base.tfm));
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_citheend_sgs:
25062306a36Sopenharmony_ci	if (areq->src == areq->dst) {
25162306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src),
25262306a36Sopenharmony_ci			     DMA_BIDIRECTIONAL);
25362306a36Sopenharmony_ci	} else {
25462306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src),
25562306a36Sopenharmony_ci			     DMA_TO_DEVICE);
25662306a36Sopenharmony_ci		dma_unmap_sg(ce->dev, areq->dst, sg_nents(areq->dst),
25762306a36Sopenharmony_ci			     DMA_FROM_DEVICE);
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_citheend:
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return err;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ciint sl3516_ce_handle_cipher_request(struct crypto_engine *engine, void *areq)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	int err;
26862306a36Sopenharmony_ci	struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	err = sl3516_ce_cipher(breq);
27162306a36Sopenharmony_ci	local_bh_disable();
27262306a36Sopenharmony_ci	crypto_finalize_skcipher_request(engine, breq, err);
27362306a36Sopenharmony_ci	local_bh_enable();
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciint sl3516_ce_skdecrypt(struct skcipher_request *areq)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
28162306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
28262306a36Sopenharmony_ci	struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
28362306a36Sopenharmony_ci	struct crypto_engine *engine;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	memset(rctx, 0, sizeof(struct sl3516_ce_cipher_req_ctx));
28662306a36Sopenharmony_ci	rctx->op_dir = CE_DECRYPTION;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (sl3516_ce_need_fallback(areq))
28962306a36Sopenharmony_ci		return sl3516_ce_cipher_fallback(areq);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	engine = op->ce->engine;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return crypto_transfer_skcipher_request_to_engine(engine, areq);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciint sl3516_ce_skencrypt(struct skcipher_request *areq)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
29962306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
30062306a36Sopenharmony_ci	struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
30162306a36Sopenharmony_ci	struct crypto_engine *engine;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	memset(rctx, 0, sizeof(struct sl3516_ce_cipher_req_ctx));
30462306a36Sopenharmony_ci	rctx->op_dir = CE_ENCRYPTION;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (sl3516_ce_need_fallback(areq))
30762306a36Sopenharmony_ci		return sl3516_ce_cipher_fallback(areq);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	engine = op->ce->engine;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return crypto_transfer_skcipher_request_to_engine(engine, areq);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ciint sl3516_ce_cipher_init(struct crypto_tfm *tfm)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
31762306a36Sopenharmony_ci	struct sl3516_ce_alg_template *algt;
31862306a36Sopenharmony_ci	const char *name = crypto_tfm_alg_name(tfm);
31962306a36Sopenharmony_ci	struct crypto_skcipher *sktfm = __crypto_skcipher_cast(tfm);
32062306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(sktfm);
32162306a36Sopenharmony_ci	int err;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	memset(op, 0, sizeof(struct sl3516_ce_cipher_tfm_ctx));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher.base);
32662306a36Sopenharmony_ci	op->ce = algt->ce;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
32962306a36Sopenharmony_ci	if (IS_ERR(op->fallback_tfm)) {
33062306a36Sopenharmony_ci		dev_err(op->ce->dev, "ERROR: Cannot allocate fallback for %s %ld\n",
33162306a36Sopenharmony_ci			name, PTR_ERR(op->fallback_tfm));
33262306a36Sopenharmony_ci		return PTR_ERR(op->fallback_tfm);
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	sktfm->reqsize = sizeof(struct sl3516_ce_cipher_req_ctx) +
33662306a36Sopenharmony_ci			 crypto_skcipher_reqsize(op->fallback_tfm);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	dev_info(op->ce->dev, "Fallback for %s is %s\n",
33962306a36Sopenharmony_ci		 crypto_tfm_alg_driver_name(&sktfm->base),
34062306a36Sopenharmony_ci		 crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)));
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	err = pm_runtime_get_sync(op->ce->dev);
34362306a36Sopenharmony_ci	if (err < 0)
34462306a36Sopenharmony_ci		goto error_pm;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_cierror_pm:
34862306a36Sopenharmony_ci	pm_runtime_put_noidle(op->ce->dev);
34962306a36Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
35062306a36Sopenharmony_ci	return err;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_civoid sl3516_ce_cipher_exit(struct crypto_tfm *tfm)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	kfree_sensitive(op->key);
35862306a36Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
35962306a36Sopenharmony_ci	pm_runtime_put_sync_suspend(op->ce->dev);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ciint sl3516_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
36362306a36Sopenharmony_ci			 unsigned int keylen)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
36662306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = op->ce;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	switch (keylen) {
36962306a36Sopenharmony_ci	case 128 / 8:
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci	case 192 / 8:
37262306a36Sopenharmony_ci		break;
37362306a36Sopenharmony_ci	case 256 / 8:
37462306a36Sopenharmony_ci		break;
37562306a36Sopenharmony_ci	default:
37662306a36Sopenharmony_ci		dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
37762306a36Sopenharmony_ci		return -EINVAL;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	kfree_sensitive(op->key);
38062306a36Sopenharmony_ci	op->keylen = keylen;
38162306a36Sopenharmony_ci	op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
38262306a36Sopenharmony_ci	if (!op->key)
38362306a36Sopenharmony_ci		return -ENOMEM;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
38662306a36Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
38962306a36Sopenharmony_ci}
390