162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * sun4i-ss-cipher.c - hardware cryptographic accelerator for Allwinner A20 SoC
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013-2015 Corentin LABBE <clabbe.montjoie@gmail.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file add support for AES cipher with 128,192,256 bits
862306a36Sopenharmony_ci * keysize in CBC and ECB mode.
962306a36Sopenharmony_ci * Add support also for DES and 3DES in CBC and ECB mode.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * You could find the datasheet in Documentation/arch/arm/sunxi.rst
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include "sun4i-ss.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int noinline_for_stack sun4i_ss_opti_poll(struct skcipher_request *areq)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
1862306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
1962306a36Sopenharmony_ci	struct sun4i_ss_ctx *ss = op->ss;
2062306a36Sopenharmony_ci	unsigned int ivsize = crypto_skcipher_ivsize(tfm);
2162306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
2262306a36Sopenharmony_ci	u32 mode = ctx->mode;
2362306a36Sopenharmony_ci	/* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */
2462306a36Sopenharmony_ci	u32 rx_cnt = SS_RX_DEFAULT;
2562306a36Sopenharmony_ci	u32 tx_cnt = 0;
2662306a36Sopenharmony_ci	u32 spaces;
2762306a36Sopenharmony_ci	u32 v;
2862306a36Sopenharmony_ci	int err = 0;
2962306a36Sopenharmony_ci	unsigned int i;
3062306a36Sopenharmony_ci	unsigned int ileft = areq->cryptlen;
3162306a36Sopenharmony_ci	unsigned int oleft = areq->cryptlen;
3262306a36Sopenharmony_ci	unsigned int todo;
3362306a36Sopenharmony_ci	unsigned long pi = 0, po = 0; /* progress for in and out */
3462306a36Sopenharmony_ci	bool miter_err;
3562306a36Sopenharmony_ci	struct sg_mapping_iter mi, mo;
3662306a36Sopenharmony_ci	unsigned int oi, oo; /* offset for in and out */
3762306a36Sopenharmony_ci	unsigned long flags;
3862306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
3962306a36Sopenharmony_ci	struct sun4i_ss_alg_template *algt;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (!areq->cryptlen)
4262306a36Sopenharmony_ci		return 0;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (!areq->src || !areq->dst) {
4562306a36Sopenharmony_ci		dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n");
4662306a36Sopenharmony_ci		return -EINVAL;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (areq->iv && ivsize > 0 && mode & SS_DECRYPTION) {
5062306a36Sopenharmony_ci		scatterwalk_map_and_copy(ctx->backup_iv, areq->src,
5162306a36Sopenharmony_ci					 areq->cryptlen - ivsize, ivsize, 0);
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
5562306a36Sopenharmony_ci		algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto);
5662306a36Sopenharmony_ci		algt->stat_opti++;
5762306a36Sopenharmony_ci		algt->stat_bytes += areq->cryptlen;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	spin_lock_irqsave(&ss->slock, flags);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	for (i = 0; i < op->keylen / 4; i++)
6362306a36Sopenharmony_ci		writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (areq->iv) {
6662306a36Sopenharmony_ci		for (i = 0; i < 4 && i < ivsize / 4; i++) {
6762306a36Sopenharmony_ci			v = *(u32 *)(areq->iv + i * 4);
6862306a36Sopenharmony_ci			writesl(ss->base + SS_IV0 + i * 4, &v, 1);
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci	writel(mode, ss->base + SS_CTL);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ileft = areq->cryptlen / 4;
7562306a36Sopenharmony_ci	oleft = areq->cryptlen / 4;
7662306a36Sopenharmony_ci	oi = 0;
7762306a36Sopenharmony_ci	oo = 0;
7862306a36Sopenharmony_ci	do {
7962306a36Sopenharmony_ci		if (ileft) {
8062306a36Sopenharmony_ci			sg_miter_start(&mi, areq->src, sg_nents(areq->src),
8162306a36Sopenharmony_ci					SG_MITER_FROM_SG | SG_MITER_ATOMIC);
8262306a36Sopenharmony_ci			if (pi)
8362306a36Sopenharmony_ci				sg_miter_skip(&mi, pi);
8462306a36Sopenharmony_ci			miter_err = sg_miter_next(&mi);
8562306a36Sopenharmony_ci			if (!miter_err || !mi.addr) {
8662306a36Sopenharmony_ci				dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
8762306a36Sopenharmony_ci				err = -EINVAL;
8862306a36Sopenharmony_ci				goto release_ss;
8962306a36Sopenharmony_ci			}
9062306a36Sopenharmony_ci			todo = min(rx_cnt, ileft);
9162306a36Sopenharmony_ci			todo = min_t(size_t, todo, (mi.length - oi) / 4);
9262306a36Sopenharmony_ci			if (todo) {
9362306a36Sopenharmony_ci				ileft -= todo;
9462306a36Sopenharmony_ci				writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo);
9562306a36Sopenharmony_ci				oi += todo * 4;
9662306a36Sopenharmony_ci			}
9762306a36Sopenharmony_ci			if (oi == mi.length) {
9862306a36Sopenharmony_ci				pi += mi.length;
9962306a36Sopenharmony_ci				oi = 0;
10062306a36Sopenharmony_ci			}
10162306a36Sopenharmony_ci			sg_miter_stop(&mi);
10262306a36Sopenharmony_ci		}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		spaces = readl(ss->base + SS_FCSR);
10562306a36Sopenharmony_ci		rx_cnt = SS_RXFIFO_SPACES(spaces);
10662306a36Sopenharmony_ci		tx_cnt = SS_TXFIFO_SPACES(spaces);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
10962306a36Sopenharmony_ci			       SG_MITER_TO_SG | SG_MITER_ATOMIC);
11062306a36Sopenharmony_ci		if (po)
11162306a36Sopenharmony_ci			sg_miter_skip(&mo, po);
11262306a36Sopenharmony_ci		miter_err = sg_miter_next(&mo);
11362306a36Sopenharmony_ci		if (!miter_err || !mo.addr) {
11462306a36Sopenharmony_ci			dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
11562306a36Sopenharmony_ci			err = -EINVAL;
11662306a36Sopenharmony_ci			goto release_ss;
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci		todo = min(tx_cnt, oleft);
11962306a36Sopenharmony_ci		todo = min_t(size_t, todo, (mo.length - oo) / 4);
12062306a36Sopenharmony_ci		if (todo) {
12162306a36Sopenharmony_ci			oleft -= todo;
12262306a36Sopenharmony_ci			readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
12362306a36Sopenharmony_ci			oo += todo * 4;
12462306a36Sopenharmony_ci		}
12562306a36Sopenharmony_ci		if (oo == mo.length) {
12662306a36Sopenharmony_ci			oo = 0;
12762306a36Sopenharmony_ci			po += mo.length;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci		sg_miter_stop(&mo);
13062306a36Sopenharmony_ci	} while (oleft);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (areq->iv) {
13362306a36Sopenharmony_ci		if (mode & SS_DECRYPTION) {
13462306a36Sopenharmony_ci			memcpy(areq->iv, ctx->backup_iv, ivsize);
13562306a36Sopenharmony_ci			memzero_explicit(ctx->backup_iv, ivsize);
13662306a36Sopenharmony_ci		} else {
13762306a36Sopenharmony_ci			scatterwalk_map_and_copy(areq->iv, areq->dst, areq->cryptlen - ivsize,
13862306a36Sopenharmony_ci						 ivsize, 0);
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cirelease_ss:
14362306a36Sopenharmony_ci	writel(0, ss->base + SS_CTL);
14462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ss->slock, flags);
14562306a36Sopenharmony_ci	return err;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int noinline_for_stack sun4i_ss_cipher_poll_fallback(struct skcipher_request *areq)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
15162306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
15262306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
15362306a36Sopenharmony_ci	int err;
15462306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
15562306a36Sopenharmony_ci	struct sun4i_ss_alg_template *algt;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
15862306a36Sopenharmony_ci		algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto);
15962306a36Sopenharmony_ci		algt->stat_fb++;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	skcipher_request_set_tfm(&ctx->fallback_req, op->fallback_tfm);
16362306a36Sopenharmony_ci	skcipher_request_set_callback(&ctx->fallback_req, areq->base.flags,
16462306a36Sopenharmony_ci				      areq->base.complete, areq->base.data);
16562306a36Sopenharmony_ci	skcipher_request_set_crypt(&ctx->fallback_req, areq->src, areq->dst,
16662306a36Sopenharmony_ci				   areq->cryptlen, areq->iv);
16762306a36Sopenharmony_ci	if (ctx->mode & SS_DECRYPTION)
16862306a36Sopenharmony_ci		err = crypto_skcipher_decrypt(&ctx->fallback_req);
16962306a36Sopenharmony_ci	else
17062306a36Sopenharmony_ci		err = crypto_skcipher_encrypt(&ctx->fallback_req);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return err;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/* Generic function that support SG with size not multiple of 4 */
17662306a36Sopenharmony_cistatic int sun4i_ss_cipher_poll(struct skcipher_request *areq)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
17962306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
18062306a36Sopenharmony_ci	struct sun4i_ss_ctx *ss = op->ss;
18162306a36Sopenharmony_ci	int no_chunk = 1;
18262306a36Sopenharmony_ci	struct scatterlist *in_sg = areq->src;
18362306a36Sopenharmony_ci	struct scatterlist *out_sg = areq->dst;
18462306a36Sopenharmony_ci	unsigned int ivsize = crypto_skcipher_ivsize(tfm);
18562306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
18662306a36Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
18762306a36Sopenharmony_ci	struct sun4i_ss_alg_template *algt;
18862306a36Sopenharmony_ci	u32 mode = ctx->mode;
18962306a36Sopenharmony_ci	/* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */
19062306a36Sopenharmony_ci	u32 rx_cnt = SS_RX_DEFAULT;
19162306a36Sopenharmony_ci	u32 tx_cnt = 0;
19262306a36Sopenharmony_ci	u32 v;
19362306a36Sopenharmony_ci	u32 spaces;
19462306a36Sopenharmony_ci	int err = 0;
19562306a36Sopenharmony_ci	unsigned int i;
19662306a36Sopenharmony_ci	unsigned int ileft = areq->cryptlen;
19762306a36Sopenharmony_ci	unsigned int oleft = areq->cryptlen;
19862306a36Sopenharmony_ci	unsigned int todo;
19962306a36Sopenharmony_ci	struct sg_mapping_iter mi, mo;
20062306a36Sopenharmony_ci	unsigned long pi = 0, po = 0; /* progress for in and out */
20162306a36Sopenharmony_ci	bool miter_err;
20262306a36Sopenharmony_ci	unsigned int oi, oo;	/* offset for in and out */
20362306a36Sopenharmony_ci	unsigned int ob = 0;	/* offset in buf */
20462306a36Sopenharmony_ci	unsigned int obo = 0;	/* offset in bufo*/
20562306a36Sopenharmony_ci	unsigned int obl = 0;	/* length of data in bufo */
20662306a36Sopenharmony_ci	unsigned long flags;
20762306a36Sopenharmony_ci	bool need_fallback = false;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (!areq->cryptlen)
21062306a36Sopenharmony_ci		return 0;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (!areq->src || !areq->dst) {
21362306a36Sopenharmony_ci		dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n");
21462306a36Sopenharmony_ci		return -EINVAL;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto);
21862306a36Sopenharmony_ci	if (areq->cryptlen % algt->alg.crypto.base.cra_blocksize)
21962306a36Sopenharmony_ci		need_fallback = true;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/*
22262306a36Sopenharmony_ci	 * if we have only SGs with size multiple of 4,
22362306a36Sopenharmony_ci	 * we can use the SS optimized function
22462306a36Sopenharmony_ci	 */
22562306a36Sopenharmony_ci	while (in_sg && no_chunk == 1) {
22662306a36Sopenharmony_ci		if ((in_sg->length | in_sg->offset) & 3u)
22762306a36Sopenharmony_ci			no_chunk = 0;
22862306a36Sopenharmony_ci		in_sg = sg_next(in_sg);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	while (out_sg && no_chunk == 1) {
23162306a36Sopenharmony_ci		if ((out_sg->length | out_sg->offset) & 3u)
23262306a36Sopenharmony_ci			no_chunk = 0;
23362306a36Sopenharmony_ci		out_sg = sg_next(out_sg);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (no_chunk == 1 && !need_fallback)
23762306a36Sopenharmony_ci		return sun4i_ss_opti_poll(areq);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (need_fallback)
24062306a36Sopenharmony_ci		return sun4i_ss_cipher_poll_fallback(areq);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (areq->iv && ivsize > 0 && mode & SS_DECRYPTION) {
24362306a36Sopenharmony_ci		scatterwalk_map_and_copy(ctx->backup_iv, areq->src,
24462306a36Sopenharmony_ci					 areq->cryptlen - ivsize, ivsize, 0);
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
24862306a36Sopenharmony_ci		algt->stat_req++;
24962306a36Sopenharmony_ci		algt->stat_bytes += areq->cryptlen;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	spin_lock_irqsave(&ss->slock, flags);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	for (i = 0; i < op->keylen / 4; i++)
25562306a36Sopenharmony_ci		writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (areq->iv) {
25862306a36Sopenharmony_ci		for (i = 0; i < 4 && i < ivsize / 4; i++) {
25962306a36Sopenharmony_ci			v = *(u32 *)(areq->iv + i * 4);
26062306a36Sopenharmony_ci			writesl(ss->base + SS_IV0 + i * 4, &v, 1);
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci	writel(mode, ss->base + SS_CTL);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ileft = areq->cryptlen;
26662306a36Sopenharmony_ci	oleft = areq->cryptlen;
26762306a36Sopenharmony_ci	oi = 0;
26862306a36Sopenharmony_ci	oo = 0;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	while (oleft) {
27162306a36Sopenharmony_ci		if (ileft) {
27262306a36Sopenharmony_ci			sg_miter_start(&mi, areq->src, sg_nents(areq->src),
27362306a36Sopenharmony_ci				       SG_MITER_FROM_SG | SG_MITER_ATOMIC);
27462306a36Sopenharmony_ci			if (pi)
27562306a36Sopenharmony_ci				sg_miter_skip(&mi, pi);
27662306a36Sopenharmony_ci			miter_err = sg_miter_next(&mi);
27762306a36Sopenharmony_ci			if (!miter_err || !mi.addr) {
27862306a36Sopenharmony_ci				dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
27962306a36Sopenharmony_ci				err = -EINVAL;
28062306a36Sopenharmony_ci				goto release_ss;
28162306a36Sopenharmony_ci			}
28262306a36Sopenharmony_ci			/*
28362306a36Sopenharmony_ci			 * todo is the number of consecutive 4byte word that we
28462306a36Sopenharmony_ci			 * can read from current SG
28562306a36Sopenharmony_ci			 */
28662306a36Sopenharmony_ci			todo = min(rx_cnt, ileft / 4);
28762306a36Sopenharmony_ci			todo = min_t(size_t, todo, (mi.length - oi) / 4);
28862306a36Sopenharmony_ci			if (todo && !ob) {
28962306a36Sopenharmony_ci				writesl(ss->base + SS_RXFIFO, mi.addr + oi,
29062306a36Sopenharmony_ci					todo);
29162306a36Sopenharmony_ci				ileft -= todo * 4;
29262306a36Sopenharmony_ci				oi += todo * 4;
29362306a36Sopenharmony_ci			} else {
29462306a36Sopenharmony_ci				/*
29562306a36Sopenharmony_ci				 * not enough consecutive bytes, so we need to
29662306a36Sopenharmony_ci				 * linearize in buf. todo is in bytes
29762306a36Sopenharmony_ci				 * After that copy, if we have a multiple of 4
29862306a36Sopenharmony_ci				 * we need to be able to write all buf in one
29962306a36Sopenharmony_ci				 * pass, so it is why we min() with rx_cnt
30062306a36Sopenharmony_ci				 */
30162306a36Sopenharmony_ci				todo = min(rx_cnt * 4 - ob, ileft);
30262306a36Sopenharmony_ci				todo = min_t(size_t, todo, mi.length - oi);
30362306a36Sopenharmony_ci				memcpy(ss->buf + ob, mi.addr + oi, todo);
30462306a36Sopenharmony_ci				ileft -= todo;
30562306a36Sopenharmony_ci				oi += todo;
30662306a36Sopenharmony_ci				ob += todo;
30762306a36Sopenharmony_ci				if (!(ob % 4)) {
30862306a36Sopenharmony_ci					writesl(ss->base + SS_RXFIFO, ss->buf,
30962306a36Sopenharmony_ci						ob / 4);
31062306a36Sopenharmony_ci					ob = 0;
31162306a36Sopenharmony_ci				}
31262306a36Sopenharmony_ci			}
31362306a36Sopenharmony_ci			if (oi == mi.length) {
31462306a36Sopenharmony_ci				pi += mi.length;
31562306a36Sopenharmony_ci				oi = 0;
31662306a36Sopenharmony_ci			}
31762306a36Sopenharmony_ci			sg_miter_stop(&mi);
31862306a36Sopenharmony_ci		}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		spaces = readl(ss->base + SS_FCSR);
32162306a36Sopenharmony_ci		rx_cnt = SS_RXFIFO_SPACES(spaces);
32262306a36Sopenharmony_ci		tx_cnt = SS_TXFIFO_SPACES(spaces);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		if (!tx_cnt)
32562306a36Sopenharmony_ci			continue;
32662306a36Sopenharmony_ci		sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
32762306a36Sopenharmony_ci			       SG_MITER_TO_SG | SG_MITER_ATOMIC);
32862306a36Sopenharmony_ci		if (po)
32962306a36Sopenharmony_ci			sg_miter_skip(&mo, po);
33062306a36Sopenharmony_ci		miter_err = sg_miter_next(&mo);
33162306a36Sopenharmony_ci		if (!miter_err || !mo.addr) {
33262306a36Sopenharmony_ci			dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
33362306a36Sopenharmony_ci			err = -EINVAL;
33462306a36Sopenharmony_ci			goto release_ss;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		/* todo in 4bytes word */
33762306a36Sopenharmony_ci		todo = min(tx_cnt, oleft / 4);
33862306a36Sopenharmony_ci		todo = min_t(size_t, todo, (mo.length - oo) / 4);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		if (todo) {
34162306a36Sopenharmony_ci			readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
34262306a36Sopenharmony_ci			oleft -= todo * 4;
34362306a36Sopenharmony_ci			oo += todo * 4;
34462306a36Sopenharmony_ci			if (oo == mo.length) {
34562306a36Sopenharmony_ci				po += mo.length;
34662306a36Sopenharmony_ci				oo = 0;
34762306a36Sopenharmony_ci			}
34862306a36Sopenharmony_ci		} else {
34962306a36Sopenharmony_ci			/*
35062306a36Sopenharmony_ci			 * read obl bytes in bufo, we read at maximum for
35162306a36Sopenharmony_ci			 * emptying the device
35262306a36Sopenharmony_ci			 */
35362306a36Sopenharmony_ci			readsl(ss->base + SS_TXFIFO, ss->bufo, tx_cnt);
35462306a36Sopenharmony_ci			obl = tx_cnt * 4;
35562306a36Sopenharmony_ci			obo = 0;
35662306a36Sopenharmony_ci			do {
35762306a36Sopenharmony_ci				/*
35862306a36Sopenharmony_ci				 * how many bytes we can copy ?
35962306a36Sopenharmony_ci				 * no more than remaining SG size
36062306a36Sopenharmony_ci				 * no more than remaining buffer
36162306a36Sopenharmony_ci				 * no need to test against oleft
36262306a36Sopenharmony_ci				 */
36362306a36Sopenharmony_ci				todo = min_t(size_t,
36462306a36Sopenharmony_ci					     mo.length - oo, obl - obo);
36562306a36Sopenharmony_ci				memcpy(mo.addr + oo, ss->bufo + obo, todo);
36662306a36Sopenharmony_ci				oleft -= todo;
36762306a36Sopenharmony_ci				obo += todo;
36862306a36Sopenharmony_ci				oo += todo;
36962306a36Sopenharmony_ci				if (oo == mo.length) {
37062306a36Sopenharmony_ci					po += mo.length;
37162306a36Sopenharmony_ci					sg_miter_next(&mo);
37262306a36Sopenharmony_ci					oo = 0;
37362306a36Sopenharmony_ci				}
37462306a36Sopenharmony_ci			} while (obo < obl);
37562306a36Sopenharmony_ci			/* bufo must be fully used here */
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci		sg_miter_stop(&mo);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	if (areq->iv) {
38062306a36Sopenharmony_ci		if (mode & SS_DECRYPTION) {
38162306a36Sopenharmony_ci			memcpy(areq->iv, ctx->backup_iv, ivsize);
38262306a36Sopenharmony_ci			memzero_explicit(ctx->backup_iv, ivsize);
38362306a36Sopenharmony_ci		} else {
38462306a36Sopenharmony_ci			scatterwalk_map_and_copy(areq->iv, areq->dst, areq->cryptlen - ivsize,
38562306a36Sopenharmony_ci						 ivsize, 0);
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cirelease_ss:
39062306a36Sopenharmony_ci	writel(0, ss->base + SS_CTL);
39162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ss->slock, flags);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return err;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/* CBC AES */
39762306a36Sopenharmony_ciint sun4i_ss_cbc_aes_encrypt(struct skcipher_request *areq)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
40062306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
40162306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_ENCRYPTION |
40462306a36Sopenharmony_ci		op->keymode;
40562306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ciint sun4i_ss_cbc_aes_decrypt(struct skcipher_request *areq)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
41162306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
41262306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_DECRYPTION |
41562306a36Sopenharmony_ci		op->keymode;
41662306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/* ECB AES */
42062306a36Sopenharmony_ciint sun4i_ss_ecb_aes_encrypt(struct skcipher_request *areq)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
42362306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
42462306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_ENCRYPTION |
42762306a36Sopenharmony_ci		op->keymode;
42862306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ciint sun4i_ss_ecb_aes_decrypt(struct skcipher_request *areq)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
43462306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
43562306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_DECRYPTION |
43862306a36Sopenharmony_ci		op->keymode;
43962306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci/* CBC DES */
44362306a36Sopenharmony_ciint sun4i_ss_cbc_des_encrypt(struct skcipher_request *areq)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
44662306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
44762306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION |
45062306a36Sopenharmony_ci		op->keymode;
45162306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ciint sun4i_ss_cbc_des_decrypt(struct skcipher_request *areq)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
45762306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
45862306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_DECRYPTION |
46162306a36Sopenharmony_ci		op->keymode;
46262306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci/* ECB DES */
46662306a36Sopenharmony_ciint sun4i_ss_ecb_des_encrypt(struct skcipher_request *areq)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
46962306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
47062306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION |
47362306a36Sopenharmony_ci		op->keymode;
47462306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ciint sun4i_ss_ecb_des_decrypt(struct skcipher_request *areq)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
48062306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
48162306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_DECRYPTION |
48462306a36Sopenharmony_ci		op->keymode;
48562306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/* CBC 3DES */
48962306a36Sopenharmony_ciint sun4i_ss_cbc_des3_encrypt(struct skcipher_request *areq)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
49262306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
49362306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION |
49662306a36Sopenharmony_ci		op->keymode;
49762306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ciint sun4i_ss_cbc_des3_decrypt(struct skcipher_request *areq)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
50362306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
50462306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_DECRYPTION |
50762306a36Sopenharmony_ci		op->keymode;
50862306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci/* ECB 3DES */
51262306a36Sopenharmony_ciint sun4i_ss_ecb_des3_encrypt(struct skcipher_request *areq)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
51562306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
51662306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION |
51962306a36Sopenharmony_ci		op->keymode;
52062306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ciint sun4i_ss_ecb_des3_decrypt(struct skcipher_request *areq)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
52662306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
52762306a36Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_DECRYPTION |
53062306a36Sopenharmony_ci		op->keymode;
53162306a36Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ciint sun4i_ss_cipher_init(struct crypto_tfm *tfm)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
53762306a36Sopenharmony_ci	struct sun4i_ss_alg_template *algt;
53862306a36Sopenharmony_ci	const char *name = crypto_tfm_alg_name(tfm);
53962306a36Sopenharmony_ci	int err;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	memset(op, 0, sizeof(struct sun4i_tfm_ctx));
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	algt = container_of(tfm->__crt_alg, struct sun4i_ss_alg_template,
54462306a36Sopenharmony_ci			    alg.crypto.base);
54562306a36Sopenharmony_ci	op->ss = algt->ss;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
54862306a36Sopenharmony_ci	if (IS_ERR(op->fallback_tfm)) {
54962306a36Sopenharmony_ci		dev_err(op->ss->dev, "ERROR: Cannot allocate fallback for %s %ld\n",
55062306a36Sopenharmony_ci			name, PTR_ERR(op->fallback_tfm));
55162306a36Sopenharmony_ci		return PTR_ERR(op->fallback_tfm);
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
55562306a36Sopenharmony_ci				    sizeof(struct sun4i_cipher_req_ctx) +
55662306a36Sopenharmony_ci				    crypto_skcipher_reqsize(op->fallback_tfm));
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	err = pm_runtime_resume_and_get(op->ss->dev);
55962306a36Sopenharmony_ci	if (err < 0)
56062306a36Sopenharmony_ci		goto error_pm;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return 0;
56362306a36Sopenharmony_cierror_pm:
56462306a36Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
56562306a36Sopenharmony_ci	return err;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_civoid sun4i_ss_cipher_exit(struct crypto_tfm *tfm)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
57362306a36Sopenharmony_ci	pm_runtime_put(op->ss->dev);
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/* check and set the AES key, prepare the mode to be used */
57762306a36Sopenharmony_ciint sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
57862306a36Sopenharmony_ci			unsigned int keylen)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
58162306a36Sopenharmony_ci	struct sun4i_ss_ctx *ss = op->ss;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	switch (keylen) {
58462306a36Sopenharmony_ci	case 128 / 8:
58562306a36Sopenharmony_ci		op->keymode = SS_AES_128BITS;
58662306a36Sopenharmony_ci		break;
58762306a36Sopenharmony_ci	case 192 / 8:
58862306a36Sopenharmony_ci		op->keymode = SS_AES_192BITS;
58962306a36Sopenharmony_ci		break;
59062306a36Sopenharmony_ci	case 256 / 8:
59162306a36Sopenharmony_ci		op->keymode = SS_AES_256BITS;
59262306a36Sopenharmony_ci		break;
59362306a36Sopenharmony_ci	default:
59462306a36Sopenharmony_ci		dev_dbg(ss->dev, "ERROR: Invalid keylen %u\n", keylen);
59562306a36Sopenharmony_ci		return -EINVAL;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci	op->keylen = keylen;
59862306a36Sopenharmony_ci	memcpy(op->key, key, keylen);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
60162306a36Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci/* check and set the DES key, prepare the mode to be used */
60762306a36Sopenharmony_ciint sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
60862306a36Sopenharmony_ci			unsigned int keylen)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
61162306a36Sopenharmony_ci	int err;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	err = verify_skcipher_des_key(tfm, key);
61462306a36Sopenharmony_ci	if (err)
61562306a36Sopenharmony_ci		return err;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	op->keylen = keylen;
61862306a36Sopenharmony_ci	memcpy(op->key, key, keylen);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
62162306a36Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci/* check and set the 3DES key, prepare the mode to be used */
62762306a36Sopenharmony_ciint sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
62862306a36Sopenharmony_ci			 unsigned int keylen)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
63162306a36Sopenharmony_ci	int err;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	err = verify_skcipher_des3_key(tfm, key);
63462306a36Sopenharmony_ci	if (err)
63562306a36Sopenharmony_ci		return err;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	op->keylen = keylen;
63862306a36Sopenharmony_ci	memcpy(op->key, key, keylen);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
64162306a36Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
64462306a36Sopenharmony_ci}
645