18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * sun4i-ss-cipher.c - hardware cryptographic accelerator for Allwinner A20 SoC
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Corentin LABBE <clabbe.montjoie@gmail.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file add support for AES cipher with 128,192,256 bits
88c2ecf20Sopenharmony_ci * keysize in CBC and ECB mode.
98c2ecf20Sopenharmony_ci * Add support also for DES and 3DES in CBC and ECB mode.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * You could find the datasheet in Documentation/arm/sunxi.rst
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include "sun4i-ss.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic int noinline_for_stack sun4i_ss_opti_poll(struct skcipher_request *areq)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
188c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
198c2ecf20Sopenharmony_ci	struct sun4i_ss_ctx *ss = op->ss;
208c2ecf20Sopenharmony_ci	unsigned int ivsize = crypto_skcipher_ivsize(tfm);
218c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
228c2ecf20Sopenharmony_ci	u32 mode = ctx->mode;
238c2ecf20Sopenharmony_ci	void *backup_iv = NULL;
248c2ecf20Sopenharmony_ci	/* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */
258c2ecf20Sopenharmony_ci	u32 rx_cnt = SS_RX_DEFAULT;
268c2ecf20Sopenharmony_ci	u32 tx_cnt = 0;
278c2ecf20Sopenharmony_ci	u32 spaces;
288c2ecf20Sopenharmony_ci	u32 v;
298c2ecf20Sopenharmony_ci	int err = 0;
308c2ecf20Sopenharmony_ci	unsigned int i;
318c2ecf20Sopenharmony_ci	unsigned int ileft = areq->cryptlen;
328c2ecf20Sopenharmony_ci	unsigned int oleft = areq->cryptlen;
338c2ecf20Sopenharmony_ci	unsigned int todo;
348c2ecf20Sopenharmony_ci	unsigned long pi = 0, po = 0; /* progress for in and out */
358c2ecf20Sopenharmony_ci	bool miter_err;
368c2ecf20Sopenharmony_ci	struct sg_mapping_iter mi, mo;
378c2ecf20Sopenharmony_ci	unsigned int oi, oo; /* offset for in and out */
388c2ecf20Sopenharmony_ci	unsigned long flags;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (!areq->cryptlen)
418c2ecf20Sopenharmony_ci		return 0;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (!areq->src || !areq->dst) {
448c2ecf20Sopenharmony_ci		dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n");
458c2ecf20Sopenharmony_ci		return -EINVAL;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (areq->iv && ivsize > 0 && mode & SS_DECRYPTION) {
498c2ecf20Sopenharmony_ci		backup_iv = kzalloc(ivsize, GFP_KERNEL);
508c2ecf20Sopenharmony_ci		if (!backup_iv)
518c2ecf20Sopenharmony_ci			return -ENOMEM;
528c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(backup_iv, areq->src, areq->cryptlen - ivsize, ivsize, 0);
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ss->slock, flags);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	for (i = 0; i < op->keylen / 4; i++)
588c2ecf20Sopenharmony_ci		writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (areq->iv) {
618c2ecf20Sopenharmony_ci		for (i = 0; i < 4 && i < ivsize / 4; i++) {
628c2ecf20Sopenharmony_ci			v = *(u32 *)(areq->iv + i * 4);
638c2ecf20Sopenharmony_ci			writesl(ss->base + SS_IV0 + i * 4, &v, 1);
648c2ecf20Sopenharmony_ci		}
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci	writel(mode, ss->base + SS_CTL);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	ileft = areq->cryptlen / 4;
708c2ecf20Sopenharmony_ci	oleft = areq->cryptlen / 4;
718c2ecf20Sopenharmony_ci	oi = 0;
728c2ecf20Sopenharmony_ci	oo = 0;
738c2ecf20Sopenharmony_ci	do {
748c2ecf20Sopenharmony_ci		if (ileft) {
758c2ecf20Sopenharmony_ci			sg_miter_start(&mi, areq->src, sg_nents(areq->src),
768c2ecf20Sopenharmony_ci					SG_MITER_FROM_SG | SG_MITER_ATOMIC);
778c2ecf20Sopenharmony_ci			if (pi)
788c2ecf20Sopenharmony_ci				sg_miter_skip(&mi, pi);
798c2ecf20Sopenharmony_ci			miter_err = sg_miter_next(&mi);
808c2ecf20Sopenharmony_ci			if (!miter_err || !mi.addr) {
818c2ecf20Sopenharmony_ci				dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
828c2ecf20Sopenharmony_ci				err = -EINVAL;
838c2ecf20Sopenharmony_ci				goto release_ss;
848c2ecf20Sopenharmony_ci			}
858c2ecf20Sopenharmony_ci			todo = min(rx_cnt, ileft);
868c2ecf20Sopenharmony_ci			todo = min_t(size_t, todo, (mi.length - oi) / 4);
878c2ecf20Sopenharmony_ci			if (todo) {
888c2ecf20Sopenharmony_ci				ileft -= todo;
898c2ecf20Sopenharmony_ci				writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo);
908c2ecf20Sopenharmony_ci				oi += todo * 4;
918c2ecf20Sopenharmony_ci			}
928c2ecf20Sopenharmony_ci			if (oi == mi.length) {
938c2ecf20Sopenharmony_ci				pi += mi.length;
948c2ecf20Sopenharmony_ci				oi = 0;
958c2ecf20Sopenharmony_ci			}
968c2ecf20Sopenharmony_ci			sg_miter_stop(&mi);
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		spaces = readl(ss->base + SS_FCSR);
1008c2ecf20Sopenharmony_ci		rx_cnt = SS_RXFIFO_SPACES(spaces);
1018c2ecf20Sopenharmony_ci		tx_cnt = SS_TXFIFO_SPACES(spaces);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
1048c2ecf20Sopenharmony_ci			       SG_MITER_TO_SG | SG_MITER_ATOMIC);
1058c2ecf20Sopenharmony_ci		if (po)
1068c2ecf20Sopenharmony_ci			sg_miter_skip(&mo, po);
1078c2ecf20Sopenharmony_ci		miter_err = sg_miter_next(&mo);
1088c2ecf20Sopenharmony_ci		if (!miter_err || !mo.addr) {
1098c2ecf20Sopenharmony_ci			dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
1108c2ecf20Sopenharmony_ci			err = -EINVAL;
1118c2ecf20Sopenharmony_ci			goto release_ss;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci		todo = min(tx_cnt, oleft);
1148c2ecf20Sopenharmony_ci		todo = min_t(size_t, todo, (mo.length - oo) / 4);
1158c2ecf20Sopenharmony_ci		if (todo) {
1168c2ecf20Sopenharmony_ci			oleft -= todo;
1178c2ecf20Sopenharmony_ci			readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
1188c2ecf20Sopenharmony_ci			oo += todo * 4;
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci		if (oo == mo.length) {
1218c2ecf20Sopenharmony_ci			oo = 0;
1228c2ecf20Sopenharmony_ci			po += mo.length;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci		sg_miter_stop(&mo);
1258c2ecf20Sopenharmony_ci	} while (oleft);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (areq->iv) {
1288c2ecf20Sopenharmony_ci		if (mode & SS_DECRYPTION) {
1298c2ecf20Sopenharmony_ci			memcpy(areq->iv, backup_iv, ivsize);
1308c2ecf20Sopenharmony_ci			kfree_sensitive(backup_iv);
1318c2ecf20Sopenharmony_ci		} else {
1328c2ecf20Sopenharmony_ci			scatterwalk_map_and_copy(areq->iv, areq->dst, areq->cryptlen - ivsize,
1338c2ecf20Sopenharmony_ci						 ivsize, 0);
1348c2ecf20Sopenharmony_ci		}
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cirelease_ss:
1388c2ecf20Sopenharmony_ci	writel(0, ss->base + SS_CTL);
1398c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ss->slock, flags);
1408c2ecf20Sopenharmony_ci	return err;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int noinline_for_stack sun4i_ss_cipher_poll_fallback(struct skcipher_request *areq)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
1478c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
1488c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
1498c2ecf20Sopenharmony_ci	int err;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	skcipher_request_set_tfm(&ctx->fallback_req, op->fallback_tfm);
1528c2ecf20Sopenharmony_ci	skcipher_request_set_callback(&ctx->fallback_req, areq->base.flags,
1538c2ecf20Sopenharmony_ci				      areq->base.complete, areq->base.data);
1548c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(&ctx->fallback_req, areq->src, areq->dst,
1558c2ecf20Sopenharmony_ci				   areq->cryptlen, areq->iv);
1568c2ecf20Sopenharmony_ci	if (ctx->mode & SS_DECRYPTION)
1578c2ecf20Sopenharmony_ci		err = crypto_skcipher_decrypt(&ctx->fallback_req);
1588c2ecf20Sopenharmony_ci	else
1598c2ecf20Sopenharmony_ci		err = crypto_skcipher_encrypt(&ctx->fallback_req);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return err;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* Generic function that support SG with size not multiple of 4 */
1658c2ecf20Sopenharmony_cistatic int sun4i_ss_cipher_poll(struct skcipher_request *areq)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
1688c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
1698c2ecf20Sopenharmony_ci	struct sun4i_ss_ctx *ss = op->ss;
1708c2ecf20Sopenharmony_ci	int no_chunk = 1;
1718c2ecf20Sopenharmony_ci	struct scatterlist *in_sg = areq->src;
1728c2ecf20Sopenharmony_ci	struct scatterlist *out_sg = areq->dst;
1738c2ecf20Sopenharmony_ci	unsigned int ivsize = crypto_skcipher_ivsize(tfm);
1748c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
1758c2ecf20Sopenharmony_ci	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
1768c2ecf20Sopenharmony_ci	struct sun4i_ss_alg_template *algt;
1778c2ecf20Sopenharmony_ci	u32 mode = ctx->mode;
1788c2ecf20Sopenharmony_ci	/* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */
1798c2ecf20Sopenharmony_ci	u32 rx_cnt = SS_RX_DEFAULT;
1808c2ecf20Sopenharmony_ci	u32 tx_cnt = 0;
1818c2ecf20Sopenharmony_ci	u32 v;
1828c2ecf20Sopenharmony_ci	u32 spaces;
1838c2ecf20Sopenharmony_ci	int err = 0;
1848c2ecf20Sopenharmony_ci	unsigned int i;
1858c2ecf20Sopenharmony_ci	unsigned int ileft = areq->cryptlen;
1868c2ecf20Sopenharmony_ci	unsigned int oleft = areq->cryptlen;
1878c2ecf20Sopenharmony_ci	unsigned int todo;
1888c2ecf20Sopenharmony_ci	void *backup_iv = NULL;
1898c2ecf20Sopenharmony_ci	struct sg_mapping_iter mi, mo;
1908c2ecf20Sopenharmony_ci	unsigned long pi = 0, po = 0; /* progress for in and out */
1918c2ecf20Sopenharmony_ci	bool miter_err;
1928c2ecf20Sopenharmony_ci	unsigned int oi, oo;	/* offset for in and out */
1938c2ecf20Sopenharmony_ci	unsigned int ob = 0;	/* offset in buf */
1948c2ecf20Sopenharmony_ci	unsigned int obo = 0;	/* offset in bufo*/
1958c2ecf20Sopenharmony_ci	unsigned int obl = 0;	/* length of data in bufo */
1968c2ecf20Sopenharmony_ci	unsigned long flags;
1978c2ecf20Sopenharmony_ci	bool need_fallback = false;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (!areq->cryptlen)
2008c2ecf20Sopenharmony_ci		return 0;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (!areq->src || !areq->dst) {
2038c2ecf20Sopenharmony_ci		dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n");
2048c2ecf20Sopenharmony_ci		return -EINVAL;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto);
2088c2ecf20Sopenharmony_ci	if (areq->cryptlen % algt->alg.crypto.base.cra_blocksize)
2098c2ecf20Sopenharmony_ci		need_fallback = true;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/*
2128c2ecf20Sopenharmony_ci	 * if we have only SGs with size multiple of 4,
2138c2ecf20Sopenharmony_ci	 * we can use the SS optimized function
2148c2ecf20Sopenharmony_ci	 */
2158c2ecf20Sopenharmony_ci	while (in_sg && no_chunk == 1) {
2168c2ecf20Sopenharmony_ci		if ((in_sg->length | in_sg->offset) & 3u)
2178c2ecf20Sopenharmony_ci			no_chunk = 0;
2188c2ecf20Sopenharmony_ci		in_sg = sg_next(in_sg);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	while (out_sg && no_chunk == 1) {
2218c2ecf20Sopenharmony_ci		if ((out_sg->length | out_sg->offset) & 3u)
2228c2ecf20Sopenharmony_ci			no_chunk = 0;
2238c2ecf20Sopenharmony_ci		out_sg = sg_next(out_sg);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (no_chunk == 1 && !need_fallback)
2278c2ecf20Sopenharmony_ci		return sun4i_ss_opti_poll(areq);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (need_fallback)
2308c2ecf20Sopenharmony_ci		return sun4i_ss_cipher_poll_fallback(areq);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (areq->iv && ivsize > 0 && mode & SS_DECRYPTION) {
2338c2ecf20Sopenharmony_ci		backup_iv = kzalloc(ivsize, GFP_KERNEL);
2348c2ecf20Sopenharmony_ci		if (!backup_iv)
2358c2ecf20Sopenharmony_ci			return -ENOMEM;
2368c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(backup_iv, areq->src, areq->cryptlen - ivsize, ivsize, 0);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ss->slock, flags);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	for (i = 0; i < op->keylen / 4; i++)
2428c2ecf20Sopenharmony_ci		writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (areq->iv) {
2458c2ecf20Sopenharmony_ci		for (i = 0; i < 4 && i < ivsize / 4; i++) {
2468c2ecf20Sopenharmony_ci			v = *(u32 *)(areq->iv + i * 4);
2478c2ecf20Sopenharmony_ci			writesl(ss->base + SS_IV0 + i * 4, &v, 1);
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	writel(mode, ss->base + SS_CTL);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	ileft = areq->cryptlen;
2538c2ecf20Sopenharmony_ci	oleft = areq->cryptlen;
2548c2ecf20Sopenharmony_ci	oi = 0;
2558c2ecf20Sopenharmony_ci	oo = 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	while (oleft) {
2588c2ecf20Sopenharmony_ci		if (ileft) {
2598c2ecf20Sopenharmony_ci			sg_miter_start(&mi, areq->src, sg_nents(areq->src),
2608c2ecf20Sopenharmony_ci				       SG_MITER_FROM_SG | SG_MITER_ATOMIC);
2618c2ecf20Sopenharmony_ci			if (pi)
2628c2ecf20Sopenharmony_ci				sg_miter_skip(&mi, pi);
2638c2ecf20Sopenharmony_ci			miter_err = sg_miter_next(&mi);
2648c2ecf20Sopenharmony_ci			if (!miter_err || !mi.addr) {
2658c2ecf20Sopenharmony_ci				dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
2668c2ecf20Sopenharmony_ci				err = -EINVAL;
2678c2ecf20Sopenharmony_ci				goto release_ss;
2688c2ecf20Sopenharmony_ci			}
2698c2ecf20Sopenharmony_ci			/*
2708c2ecf20Sopenharmony_ci			 * todo is the number of consecutive 4byte word that we
2718c2ecf20Sopenharmony_ci			 * can read from current SG
2728c2ecf20Sopenharmony_ci			 */
2738c2ecf20Sopenharmony_ci			todo = min(rx_cnt, ileft / 4);
2748c2ecf20Sopenharmony_ci			todo = min_t(size_t, todo, (mi.length - oi) / 4);
2758c2ecf20Sopenharmony_ci			if (todo && !ob) {
2768c2ecf20Sopenharmony_ci				writesl(ss->base + SS_RXFIFO, mi.addr + oi,
2778c2ecf20Sopenharmony_ci					todo);
2788c2ecf20Sopenharmony_ci				ileft -= todo * 4;
2798c2ecf20Sopenharmony_ci				oi += todo * 4;
2808c2ecf20Sopenharmony_ci			} else {
2818c2ecf20Sopenharmony_ci				/*
2828c2ecf20Sopenharmony_ci				 * not enough consecutive bytes, so we need to
2838c2ecf20Sopenharmony_ci				 * linearize in buf. todo is in bytes
2848c2ecf20Sopenharmony_ci				 * After that copy, if we have a multiple of 4
2858c2ecf20Sopenharmony_ci				 * we need to be able to write all buf in one
2868c2ecf20Sopenharmony_ci				 * pass, so it is why we min() with rx_cnt
2878c2ecf20Sopenharmony_ci				 */
2888c2ecf20Sopenharmony_ci				todo = min(rx_cnt * 4 - ob, ileft);
2898c2ecf20Sopenharmony_ci				todo = min_t(size_t, todo, mi.length - oi);
2908c2ecf20Sopenharmony_ci				memcpy(ss->buf + ob, mi.addr + oi, todo);
2918c2ecf20Sopenharmony_ci				ileft -= todo;
2928c2ecf20Sopenharmony_ci				oi += todo;
2938c2ecf20Sopenharmony_ci				ob += todo;
2948c2ecf20Sopenharmony_ci				if (!(ob % 4)) {
2958c2ecf20Sopenharmony_ci					writesl(ss->base + SS_RXFIFO, ss->buf,
2968c2ecf20Sopenharmony_ci						ob / 4);
2978c2ecf20Sopenharmony_ci					ob = 0;
2988c2ecf20Sopenharmony_ci				}
2998c2ecf20Sopenharmony_ci			}
3008c2ecf20Sopenharmony_ci			if (oi == mi.length) {
3018c2ecf20Sopenharmony_ci				pi += mi.length;
3028c2ecf20Sopenharmony_ci				oi = 0;
3038c2ecf20Sopenharmony_ci			}
3048c2ecf20Sopenharmony_ci			sg_miter_stop(&mi);
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		spaces = readl(ss->base + SS_FCSR);
3088c2ecf20Sopenharmony_ci		rx_cnt = SS_RXFIFO_SPACES(spaces);
3098c2ecf20Sopenharmony_ci		tx_cnt = SS_TXFIFO_SPACES(spaces);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci		if (!tx_cnt)
3128c2ecf20Sopenharmony_ci			continue;
3138c2ecf20Sopenharmony_ci		sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
3148c2ecf20Sopenharmony_ci			       SG_MITER_TO_SG | SG_MITER_ATOMIC);
3158c2ecf20Sopenharmony_ci		if (po)
3168c2ecf20Sopenharmony_ci			sg_miter_skip(&mo, po);
3178c2ecf20Sopenharmony_ci		miter_err = sg_miter_next(&mo);
3188c2ecf20Sopenharmony_ci		if (!miter_err || !mo.addr) {
3198c2ecf20Sopenharmony_ci			dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
3208c2ecf20Sopenharmony_ci			err = -EINVAL;
3218c2ecf20Sopenharmony_ci			goto release_ss;
3228c2ecf20Sopenharmony_ci		}
3238c2ecf20Sopenharmony_ci		/* todo in 4bytes word */
3248c2ecf20Sopenharmony_ci		todo = min(tx_cnt, oleft / 4);
3258c2ecf20Sopenharmony_ci		todo = min_t(size_t, todo, (mo.length - oo) / 4);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		if (todo) {
3288c2ecf20Sopenharmony_ci			readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
3298c2ecf20Sopenharmony_ci			oleft -= todo * 4;
3308c2ecf20Sopenharmony_ci			oo += todo * 4;
3318c2ecf20Sopenharmony_ci			if (oo == mo.length) {
3328c2ecf20Sopenharmony_ci				po += mo.length;
3338c2ecf20Sopenharmony_ci				oo = 0;
3348c2ecf20Sopenharmony_ci			}
3358c2ecf20Sopenharmony_ci		} else {
3368c2ecf20Sopenharmony_ci			/*
3378c2ecf20Sopenharmony_ci			 * read obl bytes in bufo, we read at maximum for
3388c2ecf20Sopenharmony_ci			 * emptying the device
3398c2ecf20Sopenharmony_ci			 */
3408c2ecf20Sopenharmony_ci			readsl(ss->base + SS_TXFIFO, ss->bufo, tx_cnt);
3418c2ecf20Sopenharmony_ci			obl = tx_cnt * 4;
3428c2ecf20Sopenharmony_ci			obo = 0;
3438c2ecf20Sopenharmony_ci			do {
3448c2ecf20Sopenharmony_ci				/*
3458c2ecf20Sopenharmony_ci				 * how many bytes we can copy ?
3468c2ecf20Sopenharmony_ci				 * no more than remaining SG size
3478c2ecf20Sopenharmony_ci				 * no more than remaining buffer
3488c2ecf20Sopenharmony_ci				 * no need to test against oleft
3498c2ecf20Sopenharmony_ci				 */
3508c2ecf20Sopenharmony_ci				todo = min_t(size_t,
3518c2ecf20Sopenharmony_ci					     mo.length - oo, obl - obo);
3528c2ecf20Sopenharmony_ci				memcpy(mo.addr + oo, ss->bufo + obo, todo);
3538c2ecf20Sopenharmony_ci				oleft -= todo;
3548c2ecf20Sopenharmony_ci				obo += todo;
3558c2ecf20Sopenharmony_ci				oo += todo;
3568c2ecf20Sopenharmony_ci				if (oo == mo.length) {
3578c2ecf20Sopenharmony_ci					po += mo.length;
3588c2ecf20Sopenharmony_ci					sg_miter_next(&mo);
3598c2ecf20Sopenharmony_ci					oo = 0;
3608c2ecf20Sopenharmony_ci				}
3618c2ecf20Sopenharmony_ci			} while (obo < obl);
3628c2ecf20Sopenharmony_ci			/* bufo must be fully used here */
3638c2ecf20Sopenharmony_ci		}
3648c2ecf20Sopenharmony_ci		sg_miter_stop(&mo);
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci	if (areq->iv) {
3678c2ecf20Sopenharmony_ci		if (mode & SS_DECRYPTION) {
3688c2ecf20Sopenharmony_ci			memcpy(areq->iv, backup_iv, ivsize);
3698c2ecf20Sopenharmony_ci			kfree_sensitive(backup_iv);
3708c2ecf20Sopenharmony_ci		} else {
3718c2ecf20Sopenharmony_ci			scatterwalk_map_and_copy(areq->iv, areq->dst, areq->cryptlen - ivsize,
3728c2ecf20Sopenharmony_ci						 ivsize, 0);
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cirelease_ss:
3778c2ecf20Sopenharmony_ci	writel(0, ss->base + SS_CTL);
3788c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ss->slock, flags);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return err;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci/* CBC AES */
3848c2ecf20Sopenharmony_ciint sun4i_ss_cbc_aes_encrypt(struct skcipher_request *areq)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
3878c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
3888c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_ENCRYPTION |
3918c2ecf20Sopenharmony_ci		op->keymode;
3928c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ciint sun4i_ss_cbc_aes_decrypt(struct skcipher_request *areq)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
3988c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
3998c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_DECRYPTION |
4028c2ecf20Sopenharmony_ci		op->keymode;
4038c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/* ECB AES */
4078c2ecf20Sopenharmony_ciint sun4i_ss_ecb_aes_encrypt(struct skcipher_request *areq)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4108c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4118c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_ENCRYPTION |
4148c2ecf20Sopenharmony_ci		op->keymode;
4158c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ciint sun4i_ss_ecb_aes_decrypt(struct skcipher_request *areq)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4218c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4228c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_DECRYPTION |
4258c2ecf20Sopenharmony_ci		op->keymode;
4268c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci/* CBC DES */
4308c2ecf20Sopenharmony_ciint sun4i_ss_cbc_des_encrypt(struct skcipher_request *areq)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4338c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4348c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION |
4378c2ecf20Sopenharmony_ci		op->keymode;
4388c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ciint sun4i_ss_cbc_des_decrypt(struct skcipher_request *areq)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4448c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4458c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_DECRYPTION |
4488c2ecf20Sopenharmony_ci		op->keymode;
4498c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/* ECB DES */
4538c2ecf20Sopenharmony_ciint sun4i_ss_ecb_des_encrypt(struct skcipher_request *areq)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4568c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4578c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION |
4608c2ecf20Sopenharmony_ci		op->keymode;
4618c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ciint sun4i_ss_ecb_des_decrypt(struct skcipher_request *areq)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4678c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4688c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_DECRYPTION |
4718c2ecf20Sopenharmony_ci		op->keymode;
4728c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci/* CBC 3DES */
4768c2ecf20Sopenharmony_ciint sun4i_ss_cbc_des3_encrypt(struct skcipher_request *areq)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4798c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4808c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION |
4838c2ecf20Sopenharmony_ci		op->keymode;
4848c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ciint sun4i_ss_cbc_des3_decrypt(struct skcipher_request *areq)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
4908c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
4918c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_DECRYPTION |
4948c2ecf20Sopenharmony_ci		op->keymode;
4958c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/* ECB 3DES */
4998c2ecf20Sopenharmony_ciint sun4i_ss_ecb_des3_encrypt(struct skcipher_request *areq)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
5028c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
5038c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION |
5068c2ecf20Sopenharmony_ci		op->keymode;
5078c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ciint sun4i_ss_ecb_des3_decrypt(struct skcipher_request *areq)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
5138c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
5148c2ecf20Sopenharmony_ci	struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_DECRYPTION |
5178c2ecf20Sopenharmony_ci		op->keymode;
5188c2ecf20Sopenharmony_ci	return sun4i_ss_cipher_poll(areq);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ciint sun4i_ss_cipher_init(struct crypto_tfm *tfm)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
5248c2ecf20Sopenharmony_ci	struct sun4i_ss_alg_template *algt;
5258c2ecf20Sopenharmony_ci	const char *name = crypto_tfm_alg_name(tfm);
5268c2ecf20Sopenharmony_ci	int err;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	memset(op, 0, sizeof(struct sun4i_tfm_ctx));
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	algt = container_of(tfm->__crt_alg, struct sun4i_ss_alg_template,
5318c2ecf20Sopenharmony_ci			    alg.crypto.base);
5328c2ecf20Sopenharmony_ci	op->ss = algt->ss;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
5358c2ecf20Sopenharmony_ci	if (IS_ERR(op->fallback_tfm)) {
5368c2ecf20Sopenharmony_ci		dev_err(op->ss->dev, "ERROR: Cannot allocate fallback for %s %ld\n",
5378c2ecf20Sopenharmony_ci			name, PTR_ERR(op->fallback_tfm));
5388c2ecf20Sopenharmony_ci		return PTR_ERR(op->fallback_tfm);
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
5428c2ecf20Sopenharmony_ci				    sizeof(struct sun4i_cipher_req_ctx) +
5438c2ecf20Sopenharmony_ci				    crypto_skcipher_reqsize(op->fallback_tfm));
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	err = pm_runtime_get_sync(op->ss->dev);
5478c2ecf20Sopenharmony_ci	if (err < 0)
5488c2ecf20Sopenharmony_ci		goto error_pm;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_cierror_pm:
5528c2ecf20Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
5538c2ecf20Sopenharmony_ci	return err;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_civoid sun4i_ss_cipher_exit(struct crypto_tfm *tfm)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	crypto_free_skcipher(op->fallback_tfm);
5618c2ecf20Sopenharmony_ci	pm_runtime_put(op->ss->dev);
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci/* check and set the AES key, prepare the mode to be used */
5658c2ecf20Sopenharmony_ciint sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
5668c2ecf20Sopenharmony_ci			unsigned int keylen)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
5698c2ecf20Sopenharmony_ci	struct sun4i_ss_ctx *ss = op->ss;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	switch (keylen) {
5728c2ecf20Sopenharmony_ci	case 128 / 8:
5738c2ecf20Sopenharmony_ci		op->keymode = SS_AES_128BITS;
5748c2ecf20Sopenharmony_ci		break;
5758c2ecf20Sopenharmony_ci	case 192 / 8:
5768c2ecf20Sopenharmony_ci		op->keymode = SS_AES_192BITS;
5778c2ecf20Sopenharmony_ci		break;
5788c2ecf20Sopenharmony_ci	case 256 / 8:
5798c2ecf20Sopenharmony_ci		op->keymode = SS_AES_256BITS;
5808c2ecf20Sopenharmony_ci		break;
5818c2ecf20Sopenharmony_ci	default:
5828c2ecf20Sopenharmony_ci		dev_dbg(ss->dev, "ERROR: Invalid keylen %u\n", keylen);
5838c2ecf20Sopenharmony_ci		return -EINVAL;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci	op->keylen = keylen;
5868c2ecf20Sopenharmony_ci	memcpy(op->key, key, keylen);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
5898c2ecf20Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/* check and set the DES key, prepare the mode to be used */
5958c2ecf20Sopenharmony_ciint sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
5968c2ecf20Sopenharmony_ci			unsigned int keylen)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
5998c2ecf20Sopenharmony_ci	int err;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	err = verify_skcipher_des_key(tfm, key);
6028c2ecf20Sopenharmony_ci	if (err)
6038c2ecf20Sopenharmony_ci		return err;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	op->keylen = keylen;
6068c2ecf20Sopenharmony_ci	memcpy(op->key, key, keylen);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
6098c2ecf20Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci/* check and set the 3DES key, prepare the mode to be used */
6158c2ecf20Sopenharmony_ciint sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
6168c2ecf20Sopenharmony_ci			 unsigned int keylen)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
6198c2ecf20Sopenharmony_ci	int err;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	err = verify_skcipher_des3_key(tfm, key);
6228c2ecf20Sopenharmony_ci	if (err)
6238c2ecf20Sopenharmony_ci		return err;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	op->keylen = keylen;
6268c2ecf20Sopenharmony_ci	memcpy(op->key, key, keylen);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
6298c2ecf20Sopenharmony_ci	crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci}
634