162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
862306a36Sopenharmony_ci#include <linux/interrupt.h>
962306a36Sopenharmony_ci#include <linux/moduleparam.h>
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <crypto/aes.h>
1362306a36Sopenharmony_ci#include <crypto/internal/des.h>
1462306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "cipher.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic unsigned int aes_sw_max_len = CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN;
1962306a36Sopenharmony_cimodule_param(aes_sw_max_len, uint, 0644);
2062306a36Sopenharmony_ciMODULE_PARM_DESC(aes_sw_max_len,
2162306a36Sopenharmony_ci		 "Only use hardware for AES requests larger than this "
2262306a36Sopenharmony_ci		 "[0=always use hardware; anything <16 breaks AES-GCM; default="
2362306a36Sopenharmony_ci		 __stringify(CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN)"]");
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic LIST_HEAD(skcipher_algs);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void qce_skcipher_done(void *data)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct crypto_async_request *async_req = data;
3062306a36Sopenharmony_ci	struct skcipher_request *req = skcipher_request_cast(async_req);
3162306a36Sopenharmony_ci	struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
3262306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
3362306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
3462306a36Sopenharmony_ci	struct qce_result_dump *result_buf = qce->dma.result_buf;
3562306a36Sopenharmony_ci	enum dma_data_direction dir_src, dir_dst;
3662306a36Sopenharmony_ci	u32 status;
3762306a36Sopenharmony_ci	int error;
3862306a36Sopenharmony_ci	bool diff_dst;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	diff_dst = (req->src != req->dst) ? true : false;
4162306a36Sopenharmony_ci	dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
4262306a36Sopenharmony_ci	dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	error = qce_dma_terminate_all(&qce->dma);
4562306a36Sopenharmony_ci	if (error)
4662306a36Sopenharmony_ci		dev_dbg(qce->dev, "skcipher dma termination error (%d)\n",
4762306a36Sopenharmony_ci			error);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (diff_dst)
5062306a36Sopenharmony_ci		dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
5162306a36Sopenharmony_ci	dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	sg_free_table(&rctx->dst_tbl);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	error = qce_check_status(qce, &status);
5662306a36Sopenharmony_ci	if (error < 0)
5762306a36Sopenharmony_ci		dev_dbg(qce->dev, "skcipher operation error (%x)\n", status);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	memcpy(rctx->iv, result_buf->encr_cntr_iv, rctx->ivsize);
6062306a36Sopenharmony_ci	qce->async_req_done(tmpl->qce, error);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic int
6462306a36Sopenharmony_ciqce_skcipher_async_req_handle(struct crypto_async_request *async_req)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct skcipher_request *req = skcipher_request_cast(async_req);
6762306a36Sopenharmony_ci	struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
6862306a36Sopenharmony_ci	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
6962306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
7062306a36Sopenharmony_ci	struct qce_device *qce = tmpl->qce;
7162306a36Sopenharmony_ci	enum dma_data_direction dir_src, dir_dst;
7262306a36Sopenharmony_ci	struct scatterlist *sg;
7362306a36Sopenharmony_ci	bool diff_dst;
7462306a36Sopenharmony_ci	gfp_t gfp;
7562306a36Sopenharmony_ci	int dst_nents, src_nents, ret;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	rctx->iv = req->iv;
7862306a36Sopenharmony_ci	rctx->ivsize = crypto_skcipher_ivsize(skcipher);
7962306a36Sopenharmony_ci	rctx->cryptlen = req->cryptlen;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	diff_dst = (req->src != req->dst) ? true : false;
8262306a36Sopenharmony_ci	dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
8362306a36Sopenharmony_ci	dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	rctx->src_nents = sg_nents_for_len(req->src, req->cryptlen);
8662306a36Sopenharmony_ci	if (diff_dst)
8762306a36Sopenharmony_ci		rctx->dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
8862306a36Sopenharmony_ci	else
8962306a36Sopenharmony_ci		rctx->dst_nents = rctx->src_nents;
9062306a36Sopenharmony_ci	if (rctx->src_nents < 0) {
9162306a36Sopenharmony_ci		dev_err(qce->dev, "Invalid numbers of src SG.\n");
9262306a36Sopenharmony_ci		return rctx->src_nents;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci	if (rctx->dst_nents < 0) {
9562306a36Sopenharmony_ci		dev_err(qce->dev, "Invalid numbers of dst SG.\n");
9662306a36Sopenharmony_ci		return -rctx->dst_nents;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	rctx->dst_nents += 1;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
10262306a36Sopenharmony_ci						GFP_KERNEL : GFP_ATOMIC;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
10562306a36Sopenharmony_ci	if (ret)
10662306a36Sopenharmony_ci		return ret;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, req->cryptlen);
11162306a36Sopenharmony_ci	if (IS_ERR(sg)) {
11262306a36Sopenharmony_ci		ret = PTR_ERR(sg);
11362306a36Sopenharmony_ci		goto error_free;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg,
11762306a36Sopenharmony_ci			     QCE_RESULT_BUF_SZ);
11862306a36Sopenharmony_ci	if (IS_ERR(sg)) {
11962306a36Sopenharmony_ci		ret = PTR_ERR(sg);
12062306a36Sopenharmony_ci		goto error_free;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	sg_mark_end(sg);
12462306a36Sopenharmony_ci	rctx->dst_sg = rctx->dst_tbl.sgl;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	dst_nents = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
12762306a36Sopenharmony_ci	if (!dst_nents) {
12862306a36Sopenharmony_ci		ret = -EIO;
12962306a36Sopenharmony_ci		goto error_free;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (diff_dst) {
13362306a36Sopenharmony_ci		src_nents = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
13462306a36Sopenharmony_ci		if (!src_nents) {
13562306a36Sopenharmony_ci			ret = -EIO;
13662306a36Sopenharmony_ci			goto error_unmap_dst;
13762306a36Sopenharmony_ci		}
13862306a36Sopenharmony_ci		rctx->src_sg = req->src;
13962306a36Sopenharmony_ci	} else {
14062306a36Sopenharmony_ci		rctx->src_sg = rctx->dst_sg;
14162306a36Sopenharmony_ci		src_nents = dst_nents - 1;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents,
14562306a36Sopenharmony_ci			       rctx->dst_sg, dst_nents,
14662306a36Sopenharmony_ci			       qce_skcipher_done, async_req);
14762306a36Sopenharmony_ci	if (ret)
14862306a36Sopenharmony_ci		goto error_unmap_src;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	qce_dma_issue_pending(&qce->dma);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	ret = qce_start(async_req, tmpl->crypto_alg_type);
15362306a36Sopenharmony_ci	if (ret)
15462306a36Sopenharmony_ci		goto error_terminate;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return 0;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cierror_terminate:
15962306a36Sopenharmony_ci	qce_dma_terminate_all(&qce->dma);
16062306a36Sopenharmony_cierror_unmap_src:
16162306a36Sopenharmony_ci	if (diff_dst)
16262306a36Sopenharmony_ci		dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
16362306a36Sopenharmony_cierror_unmap_dst:
16462306a36Sopenharmony_ci	dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
16562306a36Sopenharmony_cierror_free:
16662306a36Sopenharmony_ci	sg_free_table(&rctx->dst_tbl);
16762306a36Sopenharmony_ci	return ret;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int qce_skcipher_setkey(struct crypto_skcipher *ablk, const u8 *key,
17162306a36Sopenharmony_ci				 unsigned int keylen)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct crypto_tfm *tfm = crypto_skcipher_tfm(ablk);
17462306a36Sopenharmony_ci	struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
17562306a36Sopenharmony_ci	unsigned long flags = to_cipher_tmpl(ablk)->alg_flags;
17662306a36Sopenharmony_ci	unsigned int __keylen;
17762306a36Sopenharmony_ci	int ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (!key || !keylen)
18062306a36Sopenharmony_ci		return -EINVAL;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/*
18362306a36Sopenharmony_ci	 * AES XTS key1 = key2 not supported by crypto engine.
18462306a36Sopenharmony_ci	 * Revisit to request a fallback cipher in this case.
18562306a36Sopenharmony_ci	 */
18662306a36Sopenharmony_ci	if (IS_XTS(flags)) {
18762306a36Sopenharmony_ci		__keylen = keylen >> 1;
18862306a36Sopenharmony_ci		if (!memcmp(key, key + __keylen, __keylen))
18962306a36Sopenharmony_ci			return -ENOKEY;
19062306a36Sopenharmony_ci	} else {
19162306a36Sopenharmony_ci		__keylen = keylen;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	switch (__keylen) {
19562306a36Sopenharmony_ci	case AES_KEYSIZE_128:
19662306a36Sopenharmony_ci	case AES_KEYSIZE_256:
19762306a36Sopenharmony_ci		memcpy(ctx->enc_key, key, keylen);
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	case AES_KEYSIZE_192:
20062306a36Sopenharmony_ci		break;
20162306a36Sopenharmony_ci	default:
20262306a36Sopenharmony_ci		return -EINVAL;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
20662306a36Sopenharmony_ci	if (!ret)
20762306a36Sopenharmony_ci		ctx->enc_keylen = keylen;
20862306a36Sopenharmony_ci	return ret;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic int qce_des_setkey(struct crypto_skcipher *ablk, const u8 *key,
21262306a36Sopenharmony_ci			  unsigned int keylen)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(ablk);
21562306a36Sopenharmony_ci	int err;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	err = verify_skcipher_des_key(ablk, key);
21862306a36Sopenharmony_ci	if (err)
21962306a36Sopenharmony_ci		return err;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	ctx->enc_keylen = keylen;
22262306a36Sopenharmony_ci	memcpy(ctx->enc_key, key, keylen);
22362306a36Sopenharmony_ci	return 0;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int qce_des3_setkey(struct crypto_skcipher *ablk, const u8 *key,
22762306a36Sopenharmony_ci			   unsigned int keylen)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(ablk);
23062306a36Sopenharmony_ci	u32 _key[6];
23162306a36Sopenharmony_ci	int err;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	err = verify_skcipher_des3_key(ablk, key);
23462306a36Sopenharmony_ci	if (err)
23562306a36Sopenharmony_ci		return err;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/*
23862306a36Sopenharmony_ci	 * The crypto engine does not support any two keys
23962306a36Sopenharmony_ci	 * being the same for triple des algorithms. The
24062306a36Sopenharmony_ci	 * verify_skcipher_des3_key does not check for all the
24162306a36Sopenharmony_ci	 * below conditions. Return -ENOKEY in case any two keys
24262306a36Sopenharmony_ci	 * are the same. Revisit to see if a fallback cipher
24362306a36Sopenharmony_ci	 * is needed to handle this condition.
24462306a36Sopenharmony_ci	 */
24562306a36Sopenharmony_ci	memcpy(_key, key, DES3_EDE_KEY_SIZE);
24662306a36Sopenharmony_ci	if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) ||
24762306a36Sopenharmony_ci	    !((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) ||
24862306a36Sopenharmony_ci	    !((_key[0] ^ _key[4]) | (_key[1] ^ _key[5])))
24962306a36Sopenharmony_ci		return -ENOKEY;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	ctx->enc_keylen = keylen;
25262306a36Sopenharmony_ci	memcpy(ctx->enc_key, key, keylen);
25362306a36Sopenharmony_ci	return 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int qce_skcipher_crypt(struct skcipher_request *req, int encrypt)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
25962306a36Sopenharmony_ci	struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
26062306a36Sopenharmony_ci	struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
26162306a36Sopenharmony_ci	struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
26262306a36Sopenharmony_ci	unsigned int blocksize = crypto_skcipher_blocksize(tfm);
26362306a36Sopenharmony_ci	int keylen;
26462306a36Sopenharmony_ci	int ret;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	rctx->flags = tmpl->alg_flags;
26762306a36Sopenharmony_ci	rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
26862306a36Sopenharmony_ci	keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* CE does not handle 0 length messages */
27162306a36Sopenharmony_ci	if (!req->cryptlen)
27262306a36Sopenharmony_ci		return 0;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/*
27562306a36Sopenharmony_ci	 * ECB and CBC algorithms require message lengths to be
27662306a36Sopenharmony_ci	 * multiples of block size.
27762306a36Sopenharmony_ci	 */
27862306a36Sopenharmony_ci	if (IS_ECB(rctx->flags) || IS_CBC(rctx->flags))
27962306a36Sopenharmony_ci		if (!IS_ALIGNED(req->cryptlen, blocksize))
28062306a36Sopenharmony_ci			return -EINVAL;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/*
28362306a36Sopenharmony_ci	 * Conditions for requesting a fallback cipher
28462306a36Sopenharmony_ci	 * AES-192 (not supported by crypto engine (CE))
28562306a36Sopenharmony_ci	 * AES-XTS request with len <= 512 byte (not recommended to use CE)
28662306a36Sopenharmony_ci	 * AES-XTS request with len > QCE_SECTOR_SIZE and
28762306a36Sopenharmony_ci	 * is not a multiple of it.(Revisit this condition to check if it is
28862306a36Sopenharmony_ci	 * needed in all versions of CE)
28962306a36Sopenharmony_ci	 */
29062306a36Sopenharmony_ci	if (IS_AES(rctx->flags) &&
29162306a36Sopenharmony_ci	    ((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
29262306a36Sopenharmony_ci	    (IS_XTS(rctx->flags) && ((req->cryptlen <= aes_sw_max_len) ||
29362306a36Sopenharmony_ci	    (req->cryptlen > QCE_SECTOR_SIZE &&
29462306a36Sopenharmony_ci	    req->cryptlen % QCE_SECTOR_SIZE))))) {
29562306a36Sopenharmony_ci		skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
29662306a36Sopenharmony_ci		skcipher_request_set_callback(&rctx->fallback_req,
29762306a36Sopenharmony_ci					      req->base.flags,
29862306a36Sopenharmony_ci					      req->base.complete,
29962306a36Sopenharmony_ci					      req->base.data);
30062306a36Sopenharmony_ci		skcipher_request_set_crypt(&rctx->fallback_req, req->src,
30162306a36Sopenharmony_ci					   req->dst, req->cryptlen, req->iv);
30262306a36Sopenharmony_ci		ret = encrypt ? crypto_skcipher_encrypt(&rctx->fallback_req) :
30362306a36Sopenharmony_ci				crypto_skcipher_decrypt(&rctx->fallback_req);
30462306a36Sopenharmony_ci		return ret;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int qce_skcipher_encrypt(struct skcipher_request *req)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	return qce_skcipher_crypt(req, 1);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int qce_skcipher_decrypt(struct skcipher_request *req)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	return qce_skcipher_crypt(req, 0);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int qce_skcipher_init(struct crypto_skcipher *tfm)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	/* take the size without the fallback skcipher_request at the end */
32362306a36Sopenharmony_ci	crypto_skcipher_set_reqsize(tfm, offsetof(struct qce_cipher_reqctx,
32462306a36Sopenharmony_ci						  fallback_req));
32562306a36Sopenharmony_ci	return 0;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int qce_skcipher_init_fallback(struct crypto_skcipher *tfm)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(&tfm->base),
33362306a36Sopenharmony_ci					      0, CRYPTO_ALG_NEED_FALLBACK);
33462306a36Sopenharmony_ci	if (IS_ERR(ctx->fallback))
33562306a36Sopenharmony_ci		return PTR_ERR(ctx->fallback);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	crypto_skcipher_set_reqsize(tfm, sizeof(struct qce_cipher_reqctx) +
33862306a36Sopenharmony_ci					 crypto_skcipher_reqsize(ctx->fallback));
33962306a36Sopenharmony_ci	return 0;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic void qce_skcipher_exit(struct crypto_skcipher *tfm)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	crypto_free_skcipher(ctx->fallback);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistruct qce_skcipher_def {
35062306a36Sopenharmony_ci	unsigned long flags;
35162306a36Sopenharmony_ci	const char *name;
35262306a36Sopenharmony_ci	const char *drv_name;
35362306a36Sopenharmony_ci	unsigned int blocksize;
35462306a36Sopenharmony_ci	unsigned int chunksize;
35562306a36Sopenharmony_ci	unsigned int ivsize;
35662306a36Sopenharmony_ci	unsigned int min_keysize;
35762306a36Sopenharmony_ci	unsigned int max_keysize;
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic const struct qce_skcipher_def skcipher_def[] = {
36162306a36Sopenharmony_ci	{
36262306a36Sopenharmony_ci		.flags		= QCE_ALG_AES | QCE_MODE_ECB,
36362306a36Sopenharmony_ci		.name		= "ecb(aes)",
36462306a36Sopenharmony_ci		.drv_name	= "ecb-aes-qce",
36562306a36Sopenharmony_ci		.blocksize	= AES_BLOCK_SIZE,
36662306a36Sopenharmony_ci		.ivsize		= 0,
36762306a36Sopenharmony_ci		.min_keysize	= AES_MIN_KEY_SIZE,
36862306a36Sopenharmony_ci		.max_keysize	= AES_MAX_KEY_SIZE,
36962306a36Sopenharmony_ci	},
37062306a36Sopenharmony_ci	{
37162306a36Sopenharmony_ci		.flags		= QCE_ALG_AES | QCE_MODE_CBC,
37262306a36Sopenharmony_ci		.name		= "cbc(aes)",
37362306a36Sopenharmony_ci		.drv_name	= "cbc-aes-qce",
37462306a36Sopenharmony_ci		.blocksize	= AES_BLOCK_SIZE,
37562306a36Sopenharmony_ci		.ivsize		= AES_BLOCK_SIZE,
37662306a36Sopenharmony_ci		.min_keysize	= AES_MIN_KEY_SIZE,
37762306a36Sopenharmony_ci		.max_keysize	= AES_MAX_KEY_SIZE,
37862306a36Sopenharmony_ci	},
37962306a36Sopenharmony_ci	{
38062306a36Sopenharmony_ci		.flags		= QCE_ALG_AES | QCE_MODE_CTR,
38162306a36Sopenharmony_ci		.name		= "ctr(aes)",
38262306a36Sopenharmony_ci		.drv_name	= "ctr-aes-qce",
38362306a36Sopenharmony_ci		.blocksize	= 1,
38462306a36Sopenharmony_ci		.chunksize	= AES_BLOCK_SIZE,
38562306a36Sopenharmony_ci		.ivsize		= AES_BLOCK_SIZE,
38662306a36Sopenharmony_ci		.min_keysize	= AES_MIN_KEY_SIZE,
38762306a36Sopenharmony_ci		.max_keysize	= AES_MAX_KEY_SIZE,
38862306a36Sopenharmony_ci	},
38962306a36Sopenharmony_ci	{
39062306a36Sopenharmony_ci		.flags		= QCE_ALG_AES | QCE_MODE_XTS,
39162306a36Sopenharmony_ci		.name		= "xts(aes)",
39262306a36Sopenharmony_ci		.drv_name	= "xts-aes-qce",
39362306a36Sopenharmony_ci		.blocksize	= AES_BLOCK_SIZE,
39462306a36Sopenharmony_ci		.ivsize		= AES_BLOCK_SIZE,
39562306a36Sopenharmony_ci		.min_keysize	= AES_MIN_KEY_SIZE * 2,
39662306a36Sopenharmony_ci		.max_keysize	= AES_MAX_KEY_SIZE * 2,
39762306a36Sopenharmony_ci	},
39862306a36Sopenharmony_ci	{
39962306a36Sopenharmony_ci		.flags		= QCE_ALG_DES | QCE_MODE_ECB,
40062306a36Sopenharmony_ci		.name		= "ecb(des)",
40162306a36Sopenharmony_ci		.drv_name	= "ecb-des-qce",
40262306a36Sopenharmony_ci		.blocksize	= DES_BLOCK_SIZE,
40362306a36Sopenharmony_ci		.ivsize		= 0,
40462306a36Sopenharmony_ci		.min_keysize	= DES_KEY_SIZE,
40562306a36Sopenharmony_ci		.max_keysize	= DES_KEY_SIZE,
40662306a36Sopenharmony_ci	},
40762306a36Sopenharmony_ci	{
40862306a36Sopenharmony_ci		.flags		= QCE_ALG_DES | QCE_MODE_CBC,
40962306a36Sopenharmony_ci		.name		= "cbc(des)",
41062306a36Sopenharmony_ci		.drv_name	= "cbc-des-qce",
41162306a36Sopenharmony_ci		.blocksize	= DES_BLOCK_SIZE,
41262306a36Sopenharmony_ci		.ivsize		= DES_BLOCK_SIZE,
41362306a36Sopenharmony_ci		.min_keysize	= DES_KEY_SIZE,
41462306a36Sopenharmony_ci		.max_keysize	= DES_KEY_SIZE,
41562306a36Sopenharmony_ci	},
41662306a36Sopenharmony_ci	{
41762306a36Sopenharmony_ci		.flags		= QCE_ALG_3DES | QCE_MODE_ECB,
41862306a36Sopenharmony_ci		.name		= "ecb(des3_ede)",
41962306a36Sopenharmony_ci		.drv_name	= "ecb-3des-qce",
42062306a36Sopenharmony_ci		.blocksize	= DES3_EDE_BLOCK_SIZE,
42162306a36Sopenharmony_ci		.ivsize		= 0,
42262306a36Sopenharmony_ci		.min_keysize	= DES3_EDE_KEY_SIZE,
42362306a36Sopenharmony_ci		.max_keysize	= DES3_EDE_KEY_SIZE,
42462306a36Sopenharmony_ci	},
42562306a36Sopenharmony_ci	{
42662306a36Sopenharmony_ci		.flags		= QCE_ALG_3DES | QCE_MODE_CBC,
42762306a36Sopenharmony_ci		.name		= "cbc(des3_ede)",
42862306a36Sopenharmony_ci		.drv_name	= "cbc-3des-qce",
42962306a36Sopenharmony_ci		.blocksize	= DES3_EDE_BLOCK_SIZE,
43062306a36Sopenharmony_ci		.ivsize		= DES3_EDE_BLOCK_SIZE,
43162306a36Sopenharmony_ci		.min_keysize	= DES3_EDE_KEY_SIZE,
43262306a36Sopenharmony_ci		.max_keysize	= DES3_EDE_KEY_SIZE,
43362306a36Sopenharmony_ci	},
43462306a36Sopenharmony_ci};
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int qce_skcipher_register_one(const struct qce_skcipher_def *def,
43762306a36Sopenharmony_ci				       struct qce_device *qce)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct qce_alg_template *tmpl;
44062306a36Sopenharmony_ci	struct skcipher_alg *alg;
44162306a36Sopenharmony_ci	int ret;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
44462306a36Sopenharmony_ci	if (!tmpl)
44562306a36Sopenharmony_ci		return -ENOMEM;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	alg = &tmpl->alg.skcipher;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
45062306a36Sopenharmony_ci	snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
45162306a36Sopenharmony_ci		 def->drv_name);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	alg->base.cra_blocksize		= def->blocksize;
45462306a36Sopenharmony_ci	alg->chunksize			= def->chunksize;
45562306a36Sopenharmony_ci	alg->ivsize			= def->ivsize;
45662306a36Sopenharmony_ci	alg->min_keysize		= def->min_keysize;
45762306a36Sopenharmony_ci	alg->max_keysize		= def->max_keysize;
45862306a36Sopenharmony_ci	alg->setkey			= IS_3DES(def->flags) ? qce_des3_setkey :
45962306a36Sopenharmony_ci					  IS_DES(def->flags) ? qce_des_setkey :
46062306a36Sopenharmony_ci					  qce_skcipher_setkey;
46162306a36Sopenharmony_ci	alg->encrypt			= qce_skcipher_encrypt;
46262306a36Sopenharmony_ci	alg->decrypt			= qce_skcipher_decrypt;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	alg->base.cra_priority		= 300;
46562306a36Sopenharmony_ci	alg->base.cra_flags		= CRYPTO_ALG_ASYNC |
46662306a36Sopenharmony_ci					  CRYPTO_ALG_ALLOCATES_MEMORY |
46762306a36Sopenharmony_ci					  CRYPTO_ALG_KERN_DRIVER_ONLY;
46862306a36Sopenharmony_ci	alg->base.cra_ctxsize		= sizeof(struct qce_cipher_ctx);
46962306a36Sopenharmony_ci	alg->base.cra_alignmask		= 0;
47062306a36Sopenharmony_ci	alg->base.cra_module		= THIS_MODULE;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (IS_AES(def->flags)) {
47362306a36Sopenharmony_ci		alg->base.cra_flags    |= CRYPTO_ALG_NEED_FALLBACK;
47462306a36Sopenharmony_ci		alg->init		= qce_skcipher_init_fallback;
47562306a36Sopenharmony_ci		alg->exit		= qce_skcipher_exit;
47662306a36Sopenharmony_ci	} else {
47762306a36Sopenharmony_ci		alg->init		= qce_skcipher_init;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	INIT_LIST_HEAD(&tmpl->entry);
48162306a36Sopenharmony_ci	tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_SKCIPHER;
48262306a36Sopenharmony_ci	tmpl->alg_flags = def->flags;
48362306a36Sopenharmony_ci	tmpl->qce = qce;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	ret = crypto_register_skcipher(alg);
48662306a36Sopenharmony_ci	if (ret) {
48762306a36Sopenharmony_ci		dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name);
48862306a36Sopenharmony_ci		kfree(tmpl);
48962306a36Sopenharmony_ci		return ret;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	list_add_tail(&tmpl->entry, &skcipher_algs);
49362306a36Sopenharmony_ci	dev_dbg(qce->dev, "%s is registered\n", alg->base.cra_name);
49462306a36Sopenharmony_ci	return 0;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic void qce_skcipher_unregister(struct qce_device *qce)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	struct qce_alg_template *tmpl, *n;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	list_for_each_entry_safe(tmpl, n, &skcipher_algs, entry) {
50262306a36Sopenharmony_ci		crypto_unregister_skcipher(&tmpl->alg.skcipher);
50362306a36Sopenharmony_ci		list_del(&tmpl->entry);
50462306a36Sopenharmony_ci		kfree(tmpl);
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int qce_skcipher_register(struct qce_device *qce)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	int ret, i;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(skcipher_def); i++) {
51362306a36Sopenharmony_ci		ret = qce_skcipher_register_one(&skcipher_def[i], qce);
51462306a36Sopenharmony_ci		if (ret)
51562306a36Sopenharmony_ci			goto err;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	return 0;
51962306a36Sopenharmony_cierr:
52062306a36Sopenharmony_ci	qce_skcipher_unregister(qce);
52162306a36Sopenharmony_ci	return ret;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ciconst struct qce_algo_ops skcipher_ops = {
52562306a36Sopenharmony_ci	.type = CRYPTO_ALG_TYPE_SKCIPHER,
52662306a36Sopenharmony_ci	.register_algs = qce_skcipher_register,
52762306a36Sopenharmony_ci	.unregister_algs = qce_skcipher_unregister,
52862306a36Sopenharmony_ci	.async_req_handle = qce_skcipher_async_req_handle,
52962306a36Sopenharmony_ci};
530