18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Cryptographic API.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * s390 implementation of the AES Cipher Algorithm.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * s390 Version:
88c2ecf20Sopenharmony_ci *   Copyright IBM Corp. 2005, 2017
98c2ecf20Sopenharmony_ci *   Author(s): Jan Glauber (jang@de.ibm.com)
108c2ecf20Sopenharmony_ci *		Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback
118c2ecf20Sopenharmony_ci *		Patrick Steuer <patrick.steuer@de.ibm.com>
128c2ecf20Sopenharmony_ci *		Harald Freudenberger <freude@de.ibm.com>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Derived from "crypto/aes_generic.c"
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "aes_s390"
188c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <crypto/aes.h>
218c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
228c2ecf20Sopenharmony_ci#include <crypto/ghash.h>
238c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h>
248c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
258c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
268c2ecf20Sopenharmony_ci#include <linux/err.h>
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/cpufeature.h>
298c2ecf20Sopenharmony_ci#include <linux/init.h>
308c2ecf20Sopenharmony_ci#include <linux/mutex.h>
318c2ecf20Sopenharmony_ci#include <linux/fips.h>
328c2ecf20Sopenharmony_ci#include <linux/string.h>
338c2ecf20Sopenharmony_ci#include <crypto/xts.h>
348c2ecf20Sopenharmony_ci#include <asm/cpacf.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic u8 *ctrblk;
378c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions,
408c2ecf20Sopenharmony_ci		    kma_functions;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct s390_aes_ctx {
438c2ecf20Sopenharmony_ci	u8 key[AES_MAX_KEY_SIZE];
448c2ecf20Sopenharmony_ci	int key_len;
458c2ecf20Sopenharmony_ci	unsigned long fc;
468c2ecf20Sopenharmony_ci	union {
478c2ecf20Sopenharmony_ci		struct crypto_skcipher *skcipher;
488c2ecf20Sopenharmony_ci		struct crypto_cipher *cip;
498c2ecf20Sopenharmony_ci	} fallback;
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistruct s390_xts_ctx {
538c2ecf20Sopenharmony_ci	u8 key[32];
548c2ecf20Sopenharmony_ci	u8 pcc_key[32];
558c2ecf20Sopenharmony_ci	int key_len;
568c2ecf20Sopenharmony_ci	unsigned long fc;
578c2ecf20Sopenharmony_ci	struct crypto_skcipher *fallback;
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct gcm_sg_walk {
618c2ecf20Sopenharmony_ci	struct scatter_walk walk;
628c2ecf20Sopenharmony_ci	unsigned int walk_bytes;
638c2ecf20Sopenharmony_ci	u8 *walk_ptr;
648c2ecf20Sopenharmony_ci	unsigned int walk_bytes_remain;
658c2ecf20Sopenharmony_ci	u8 buf[AES_BLOCK_SIZE];
668c2ecf20Sopenharmony_ci	unsigned int buf_bytes;
678c2ecf20Sopenharmony_ci	u8 *ptr;
688c2ecf20Sopenharmony_ci	unsigned int nbytes;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
728c2ecf20Sopenharmony_ci		unsigned int key_len)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	sctx->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
778c2ecf20Sopenharmony_ci	sctx->fallback.cip->base.crt_flags |= (tfm->crt_flags &
788c2ecf20Sopenharmony_ci			CRYPTO_TFM_REQ_MASK);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
848c2ecf20Sopenharmony_ci		       unsigned int key_len)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
878c2ecf20Sopenharmony_ci	unsigned long fc;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the key length */
908c2ecf20Sopenharmony_ci	fc = (key_len == 16) ? CPACF_KM_AES_128 :
918c2ecf20Sopenharmony_ci	     (key_len == 24) ? CPACF_KM_AES_192 :
928c2ecf20Sopenharmony_ci	     (key_len == 32) ? CPACF_KM_AES_256 : 0;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* Check if the function code is available */
958c2ecf20Sopenharmony_ci	sctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
968c2ecf20Sopenharmony_ci	if (!sctx->fc)
978c2ecf20Sopenharmony_ci		return setkey_fallback_cip(tfm, in_key, key_len);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	sctx->key_len = key_len;
1008c2ecf20Sopenharmony_ci	memcpy(sctx->key, in_key, key_len);
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (unlikely(!sctx->fc)) {
1098c2ecf20Sopenharmony_ci		crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
1108c2ecf20Sopenharmony_ci		return;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci	cpacf_km(sctx->fc, &sctx->key, out, in, AES_BLOCK_SIZE);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (unlikely(!sctx->fc)) {
1208c2ecf20Sopenharmony_ci		crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
1218c2ecf20Sopenharmony_ci		return;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci	cpacf_km(sctx->fc | CPACF_DECRYPT,
1248c2ecf20Sopenharmony_ci		 &sctx->key, out, in, AES_BLOCK_SIZE);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int fallback_init_cip(struct crypto_tfm *tfm)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	const char *name = tfm->__crt_alg->cra_name;
1308c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	sctx->fallback.cip = crypto_alloc_cipher(name, 0,
1338c2ecf20Sopenharmony_ci						 CRYPTO_ALG_NEED_FALLBACK);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (IS_ERR(sctx->fallback.cip)) {
1368c2ecf20Sopenharmony_ci		pr_err("Allocating AES fallback algorithm %s failed\n",
1378c2ecf20Sopenharmony_ci		       name);
1388c2ecf20Sopenharmony_ci		return PTR_ERR(sctx->fallback.cip);
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void fallback_exit_cip(struct crypto_tfm *tfm)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	crypto_free_cipher(sctx->fallback.cip);
1498c2ecf20Sopenharmony_ci	sctx->fallback.cip = NULL;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic struct crypto_alg aes_alg = {
1538c2ecf20Sopenharmony_ci	.cra_name		=	"aes",
1548c2ecf20Sopenharmony_ci	.cra_driver_name	=	"aes-s390",
1558c2ecf20Sopenharmony_ci	.cra_priority		=	300,
1568c2ecf20Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER |
1578c2ecf20Sopenharmony_ci					CRYPTO_ALG_NEED_FALLBACK,
1588c2ecf20Sopenharmony_ci	.cra_blocksize		=	AES_BLOCK_SIZE,
1598c2ecf20Sopenharmony_ci	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
1608c2ecf20Sopenharmony_ci	.cra_module		=	THIS_MODULE,
1618c2ecf20Sopenharmony_ci	.cra_init               =       fallback_init_cip,
1628c2ecf20Sopenharmony_ci	.cra_exit               =       fallback_exit_cip,
1638c2ecf20Sopenharmony_ci	.cra_u			=	{
1648c2ecf20Sopenharmony_ci		.cipher = {
1658c2ecf20Sopenharmony_ci			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
1668c2ecf20Sopenharmony_ci			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
1678c2ecf20Sopenharmony_ci			.cia_setkey		=	aes_set_key,
1688c2ecf20Sopenharmony_ci			.cia_encrypt		=	crypto_aes_encrypt,
1698c2ecf20Sopenharmony_ci			.cia_decrypt		=	crypto_aes_decrypt,
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci};
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int setkey_fallback_skcipher(struct crypto_skcipher *tfm, const u8 *key,
1758c2ecf20Sopenharmony_ci				    unsigned int len)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	crypto_skcipher_clear_flags(sctx->fallback.skcipher,
1808c2ecf20Sopenharmony_ci				    CRYPTO_TFM_REQ_MASK);
1818c2ecf20Sopenharmony_ci	crypto_skcipher_set_flags(sctx->fallback.skcipher,
1828c2ecf20Sopenharmony_ci				  crypto_skcipher_get_flags(tfm) &
1838c2ecf20Sopenharmony_ci				  CRYPTO_TFM_REQ_MASK);
1848c2ecf20Sopenharmony_ci	return crypto_skcipher_setkey(sctx->fallback.skcipher, key, len);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int fallback_skcipher_crypt(struct s390_aes_ctx *sctx,
1888c2ecf20Sopenharmony_ci				   struct skcipher_request *req,
1898c2ecf20Sopenharmony_ci				   unsigned long modifier)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct skcipher_request *subreq = skcipher_request_ctx(req);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	*subreq = *req;
1948c2ecf20Sopenharmony_ci	skcipher_request_set_tfm(subreq, sctx->fallback.skcipher);
1958c2ecf20Sopenharmony_ci	return (modifier & CPACF_DECRYPT) ?
1968c2ecf20Sopenharmony_ci		crypto_skcipher_decrypt(subreq) :
1978c2ecf20Sopenharmony_ci		crypto_skcipher_encrypt(subreq);
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int ecb_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
2018c2ecf20Sopenharmony_ci			   unsigned int key_len)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
2048c2ecf20Sopenharmony_ci	unsigned long fc;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the key length */
2078c2ecf20Sopenharmony_ci	fc = (key_len == 16) ? CPACF_KM_AES_128 :
2088c2ecf20Sopenharmony_ci	     (key_len == 24) ? CPACF_KM_AES_192 :
2098c2ecf20Sopenharmony_ci	     (key_len == 32) ? CPACF_KM_AES_256 : 0;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Check if the function code is available */
2128c2ecf20Sopenharmony_ci	sctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
2138c2ecf20Sopenharmony_ci	if (!sctx->fc)
2148c2ecf20Sopenharmony_ci		return setkey_fallback_skcipher(tfm, in_key, key_len);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	sctx->key_len = key_len;
2178c2ecf20Sopenharmony_ci	memcpy(sctx->key, in_key, key_len);
2188c2ecf20Sopenharmony_ci	return 0;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int ecb_aes_crypt(struct skcipher_request *req, unsigned long modifier)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2248c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
2258c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2268c2ecf20Sopenharmony_ci	unsigned int nbytes, n;
2278c2ecf20Sopenharmony_ci	int ret;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (unlikely(!sctx->fc))
2308c2ecf20Sopenharmony_ci		return fallback_skcipher_crypt(sctx, req, modifier);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
2338c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
2348c2ecf20Sopenharmony_ci		/* only use complete blocks */
2358c2ecf20Sopenharmony_ci		n = nbytes & ~(AES_BLOCK_SIZE - 1);
2368c2ecf20Sopenharmony_ci		cpacf_km(sctx->fc | modifier, sctx->key,
2378c2ecf20Sopenharmony_ci			 walk.dst.virt.addr, walk.src.virt.addr, n);
2388c2ecf20Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci	return ret;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int ecb_aes_encrypt(struct skcipher_request *req)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	return ecb_aes_crypt(req, 0);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int ecb_aes_decrypt(struct skcipher_request *req)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	return ecb_aes_crypt(req, CPACF_DECRYPT);
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int fallback_init_skcipher(struct crypto_skcipher *tfm)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	const char *name = crypto_tfm_alg_name(&tfm->base);
2568c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	sctx->fallback.skcipher = crypto_alloc_skcipher(name, 0,
2598c2ecf20Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (IS_ERR(sctx->fallback.skcipher)) {
2628c2ecf20Sopenharmony_ci		pr_err("Allocating AES fallback algorithm %s failed\n",
2638c2ecf20Sopenharmony_ci		       name);
2648c2ecf20Sopenharmony_ci		return PTR_ERR(sctx->fallback.skcipher);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
2688c2ecf20Sopenharmony_ci				    crypto_skcipher_reqsize(sctx->fallback.skcipher));
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic void fallback_exit_skcipher(struct crypto_skcipher *tfm)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	crypto_free_skcipher(sctx->fallback.skcipher);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_aes_alg = {
2808c2ecf20Sopenharmony_ci	.base.cra_name		=	"ecb(aes)",
2818c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"ecb-aes-s390",
2828c2ecf20Sopenharmony_ci	.base.cra_priority	=	401,	/* combo: aes + ecb + 1 */
2838c2ecf20Sopenharmony_ci	.base.cra_flags		=	CRYPTO_ALG_NEED_FALLBACK,
2848c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
2858c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_aes_ctx),
2868c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
2878c2ecf20Sopenharmony_ci	.init			=	fallback_init_skcipher,
2888c2ecf20Sopenharmony_ci	.exit			=	fallback_exit_skcipher,
2898c2ecf20Sopenharmony_ci	.min_keysize		=	AES_MIN_KEY_SIZE,
2908c2ecf20Sopenharmony_ci	.max_keysize		=	AES_MAX_KEY_SIZE,
2918c2ecf20Sopenharmony_ci	.setkey			=	ecb_aes_set_key,
2928c2ecf20Sopenharmony_ci	.encrypt		=	ecb_aes_encrypt,
2938c2ecf20Sopenharmony_ci	.decrypt		=	ecb_aes_decrypt,
2948c2ecf20Sopenharmony_ci};
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic int cbc_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
2978c2ecf20Sopenharmony_ci			   unsigned int key_len)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
3008c2ecf20Sopenharmony_ci	unsigned long fc;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the key length */
3038c2ecf20Sopenharmony_ci	fc = (key_len == 16) ? CPACF_KMC_AES_128 :
3048c2ecf20Sopenharmony_ci	     (key_len == 24) ? CPACF_KMC_AES_192 :
3058c2ecf20Sopenharmony_ci	     (key_len == 32) ? CPACF_KMC_AES_256 : 0;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/* Check if the function code is available */
3088c2ecf20Sopenharmony_ci	sctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0;
3098c2ecf20Sopenharmony_ci	if (!sctx->fc)
3108c2ecf20Sopenharmony_ci		return setkey_fallback_skcipher(tfm, in_key, key_len);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	sctx->key_len = key_len;
3138c2ecf20Sopenharmony_ci	memcpy(sctx->key, in_key, key_len);
3148c2ecf20Sopenharmony_ci	return 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int cbc_aes_crypt(struct skcipher_request *req, unsigned long modifier)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
3208c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
3218c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
3228c2ecf20Sopenharmony_ci	unsigned int nbytes, n;
3238c2ecf20Sopenharmony_ci	int ret;
3248c2ecf20Sopenharmony_ci	struct {
3258c2ecf20Sopenharmony_ci		u8 iv[AES_BLOCK_SIZE];
3268c2ecf20Sopenharmony_ci		u8 key[AES_MAX_KEY_SIZE];
3278c2ecf20Sopenharmony_ci	} param;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (unlikely(!sctx->fc))
3308c2ecf20Sopenharmony_ci		return fallback_skcipher_crypt(sctx, req, modifier);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
3338c2ecf20Sopenharmony_ci	if (ret)
3348c2ecf20Sopenharmony_ci		return ret;
3358c2ecf20Sopenharmony_ci	memcpy(param.iv, walk.iv, AES_BLOCK_SIZE);
3368c2ecf20Sopenharmony_ci	memcpy(param.key, sctx->key, sctx->key_len);
3378c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
3388c2ecf20Sopenharmony_ci		/* only use complete blocks */
3398c2ecf20Sopenharmony_ci		n = nbytes & ~(AES_BLOCK_SIZE - 1);
3408c2ecf20Sopenharmony_ci		cpacf_kmc(sctx->fc | modifier, &param,
3418c2ecf20Sopenharmony_ci			  walk.dst.virt.addr, walk.src.virt.addr, n);
3428c2ecf20Sopenharmony_ci		memcpy(walk.iv, param.iv, AES_BLOCK_SIZE);
3438c2ecf20Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci	memzero_explicit(&param, sizeof(param));
3468c2ecf20Sopenharmony_ci	return ret;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int cbc_aes_encrypt(struct skcipher_request *req)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	return cbc_aes_crypt(req, 0);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int cbc_aes_decrypt(struct skcipher_request *req)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	return cbc_aes_crypt(req, CPACF_DECRYPT);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_aes_alg = {
3608c2ecf20Sopenharmony_ci	.base.cra_name		=	"cbc(aes)",
3618c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"cbc-aes-s390",
3628c2ecf20Sopenharmony_ci	.base.cra_priority	=	402,	/* ecb-aes-s390 + 1 */
3638c2ecf20Sopenharmony_ci	.base.cra_flags		=	CRYPTO_ALG_NEED_FALLBACK,
3648c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
3658c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_aes_ctx),
3668c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
3678c2ecf20Sopenharmony_ci	.init			=	fallback_init_skcipher,
3688c2ecf20Sopenharmony_ci	.exit			=	fallback_exit_skcipher,
3698c2ecf20Sopenharmony_ci	.min_keysize		=	AES_MIN_KEY_SIZE,
3708c2ecf20Sopenharmony_ci	.max_keysize		=	AES_MAX_KEY_SIZE,
3718c2ecf20Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
3728c2ecf20Sopenharmony_ci	.setkey			=	cbc_aes_set_key,
3738c2ecf20Sopenharmony_ci	.encrypt		=	cbc_aes_encrypt,
3748c2ecf20Sopenharmony_ci	.decrypt		=	cbc_aes_decrypt,
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic int xts_fallback_setkey(struct crypto_skcipher *tfm, const u8 *key,
3788c2ecf20Sopenharmony_ci			       unsigned int len)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	crypto_skcipher_clear_flags(xts_ctx->fallback, CRYPTO_TFM_REQ_MASK);
3838c2ecf20Sopenharmony_ci	crypto_skcipher_set_flags(xts_ctx->fallback,
3848c2ecf20Sopenharmony_ci				  crypto_skcipher_get_flags(tfm) &
3858c2ecf20Sopenharmony_ci				  CRYPTO_TFM_REQ_MASK);
3868c2ecf20Sopenharmony_ci	return crypto_skcipher_setkey(xts_ctx->fallback, key, len);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int xts_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
3908c2ecf20Sopenharmony_ci			   unsigned int key_len)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
3938c2ecf20Sopenharmony_ci	unsigned long fc;
3948c2ecf20Sopenharmony_ci	int err;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	err = xts_fallback_setkey(tfm, in_key, key_len);
3978c2ecf20Sopenharmony_ci	if (err)
3988c2ecf20Sopenharmony_ci		return err;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* In fips mode only 128 bit or 256 bit keys are valid */
4018c2ecf20Sopenharmony_ci	if (fips_enabled && key_len != 32 && key_len != 64)
4028c2ecf20Sopenharmony_ci		return -EINVAL;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the key length */
4058c2ecf20Sopenharmony_ci	fc = (key_len == 32) ? CPACF_KM_XTS_128 :
4068c2ecf20Sopenharmony_ci	     (key_len == 64) ? CPACF_KM_XTS_256 : 0;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/* Check if the function code is available */
4098c2ecf20Sopenharmony_ci	xts_ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
4108c2ecf20Sopenharmony_ci	if (!xts_ctx->fc)
4118c2ecf20Sopenharmony_ci		return 0;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/* Split the XTS key into the two subkeys */
4148c2ecf20Sopenharmony_ci	key_len = key_len / 2;
4158c2ecf20Sopenharmony_ci	xts_ctx->key_len = key_len;
4168c2ecf20Sopenharmony_ci	memcpy(xts_ctx->key, in_key, key_len);
4178c2ecf20Sopenharmony_ci	memcpy(xts_ctx->pcc_key, in_key + key_len, key_len);
4188c2ecf20Sopenharmony_ci	return 0;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic int xts_aes_crypt(struct skcipher_request *req, unsigned long modifier)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
4248c2ecf20Sopenharmony_ci	struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
4258c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
4268c2ecf20Sopenharmony_ci	unsigned int offset, nbytes, n;
4278c2ecf20Sopenharmony_ci	int ret;
4288c2ecf20Sopenharmony_ci	struct {
4298c2ecf20Sopenharmony_ci		u8 key[32];
4308c2ecf20Sopenharmony_ci		u8 tweak[16];
4318c2ecf20Sopenharmony_ci		u8 block[16];
4328c2ecf20Sopenharmony_ci		u8 bit[16];
4338c2ecf20Sopenharmony_ci		u8 xts[16];
4348c2ecf20Sopenharmony_ci	} pcc_param;
4358c2ecf20Sopenharmony_ci	struct {
4368c2ecf20Sopenharmony_ci		u8 key[32];
4378c2ecf20Sopenharmony_ci		u8 init[16];
4388c2ecf20Sopenharmony_ci	} xts_param;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (req->cryptlen < AES_BLOCK_SIZE)
4418c2ecf20Sopenharmony_ci		return -EINVAL;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (unlikely(!xts_ctx->fc || (req->cryptlen % AES_BLOCK_SIZE) != 0)) {
4448c2ecf20Sopenharmony_ci		struct skcipher_request *subreq = skcipher_request_ctx(req);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		*subreq = *req;
4478c2ecf20Sopenharmony_ci		skcipher_request_set_tfm(subreq, xts_ctx->fallback);
4488c2ecf20Sopenharmony_ci		return (modifier & CPACF_DECRYPT) ?
4498c2ecf20Sopenharmony_ci			crypto_skcipher_decrypt(subreq) :
4508c2ecf20Sopenharmony_ci			crypto_skcipher_encrypt(subreq);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
4548c2ecf20Sopenharmony_ci	if (ret)
4558c2ecf20Sopenharmony_ci		return ret;
4568c2ecf20Sopenharmony_ci	offset = xts_ctx->key_len & 0x10;
4578c2ecf20Sopenharmony_ci	memset(pcc_param.block, 0, sizeof(pcc_param.block));
4588c2ecf20Sopenharmony_ci	memset(pcc_param.bit, 0, sizeof(pcc_param.bit));
4598c2ecf20Sopenharmony_ci	memset(pcc_param.xts, 0, sizeof(pcc_param.xts));
4608c2ecf20Sopenharmony_ci	memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak));
4618c2ecf20Sopenharmony_ci	memcpy(pcc_param.key + offset, xts_ctx->pcc_key, xts_ctx->key_len);
4628c2ecf20Sopenharmony_ci	cpacf_pcc(xts_ctx->fc, pcc_param.key + offset);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	memcpy(xts_param.key + offset, xts_ctx->key, xts_ctx->key_len);
4658c2ecf20Sopenharmony_ci	memcpy(xts_param.init, pcc_param.xts, 16);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
4688c2ecf20Sopenharmony_ci		/* only use complete blocks */
4698c2ecf20Sopenharmony_ci		n = nbytes & ~(AES_BLOCK_SIZE - 1);
4708c2ecf20Sopenharmony_ci		cpacf_km(xts_ctx->fc | modifier, xts_param.key + offset,
4718c2ecf20Sopenharmony_ci			 walk.dst.virt.addr, walk.src.virt.addr, n);
4728c2ecf20Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	memzero_explicit(&pcc_param, sizeof(pcc_param));
4758c2ecf20Sopenharmony_ci	memzero_explicit(&xts_param, sizeof(xts_param));
4768c2ecf20Sopenharmony_ci	return ret;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic int xts_aes_encrypt(struct skcipher_request *req)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	return xts_aes_crypt(req, 0);
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int xts_aes_decrypt(struct skcipher_request *req)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	return xts_aes_crypt(req, CPACF_DECRYPT);
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic int xts_fallback_init(struct crypto_skcipher *tfm)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	const char *name = crypto_tfm_alg_name(&tfm->base);
4928c2ecf20Sopenharmony_ci	struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	xts_ctx->fallback = crypto_alloc_skcipher(name, 0,
4958c2ecf20Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (IS_ERR(xts_ctx->fallback)) {
4988c2ecf20Sopenharmony_ci		pr_err("Allocating XTS fallback algorithm %s failed\n",
4998c2ecf20Sopenharmony_ci		       name);
5008c2ecf20Sopenharmony_ci		return PTR_ERR(xts_ctx->fallback);
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci	crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
5038c2ecf20Sopenharmony_ci				    crypto_skcipher_reqsize(xts_ctx->fallback));
5048c2ecf20Sopenharmony_ci	return 0;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic void xts_fallback_exit(struct crypto_skcipher *tfm)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	crypto_free_skcipher(xts_ctx->fallback);
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic struct skcipher_alg xts_aes_alg = {
5158c2ecf20Sopenharmony_ci	.base.cra_name		=	"xts(aes)",
5168c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"xts-aes-s390",
5178c2ecf20Sopenharmony_ci	.base.cra_priority	=	402,	/* ecb-aes-s390 + 1 */
5188c2ecf20Sopenharmony_ci	.base.cra_flags		=	CRYPTO_ALG_NEED_FALLBACK,
5198c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
5208c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_xts_ctx),
5218c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
5228c2ecf20Sopenharmony_ci	.init			=	xts_fallback_init,
5238c2ecf20Sopenharmony_ci	.exit			=	xts_fallback_exit,
5248c2ecf20Sopenharmony_ci	.min_keysize		=	2 * AES_MIN_KEY_SIZE,
5258c2ecf20Sopenharmony_ci	.max_keysize		=	2 * AES_MAX_KEY_SIZE,
5268c2ecf20Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
5278c2ecf20Sopenharmony_ci	.setkey			=	xts_aes_set_key,
5288c2ecf20Sopenharmony_ci	.encrypt		=	xts_aes_encrypt,
5298c2ecf20Sopenharmony_ci	.decrypt		=	xts_aes_decrypt,
5308c2ecf20Sopenharmony_ci};
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic int ctr_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
5338c2ecf20Sopenharmony_ci			   unsigned int key_len)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
5368c2ecf20Sopenharmony_ci	unsigned long fc;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the key length */
5398c2ecf20Sopenharmony_ci	fc = (key_len == 16) ? CPACF_KMCTR_AES_128 :
5408c2ecf20Sopenharmony_ci	     (key_len == 24) ? CPACF_KMCTR_AES_192 :
5418c2ecf20Sopenharmony_ci	     (key_len == 32) ? CPACF_KMCTR_AES_256 : 0;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* Check if the function code is available */
5448c2ecf20Sopenharmony_ci	sctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0;
5458c2ecf20Sopenharmony_ci	if (!sctx->fc)
5468c2ecf20Sopenharmony_ci		return setkey_fallback_skcipher(tfm, in_key, key_len);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	sctx->key_len = key_len;
5498c2ecf20Sopenharmony_ci	memcpy(sctx->key, in_key, key_len);
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	unsigned int i, n;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/* only use complete blocks, max. PAGE_SIZE */
5588c2ecf20Sopenharmony_ci	memcpy(ctrptr, iv, AES_BLOCK_SIZE);
5598c2ecf20Sopenharmony_ci	n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1);
5608c2ecf20Sopenharmony_ci	for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) {
5618c2ecf20Sopenharmony_ci		memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE);
5628c2ecf20Sopenharmony_ci		crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
5638c2ecf20Sopenharmony_ci		ctrptr += AES_BLOCK_SIZE;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci	return n;
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic int ctr_aes_crypt(struct skcipher_request *req)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
5718c2ecf20Sopenharmony_ci	struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
5728c2ecf20Sopenharmony_ci	u8 buf[AES_BLOCK_SIZE], *ctrptr;
5738c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
5748c2ecf20Sopenharmony_ci	unsigned int n, nbytes;
5758c2ecf20Sopenharmony_ci	int ret, locked;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (unlikely(!sctx->fc))
5788c2ecf20Sopenharmony_ci		return fallback_skcipher_crypt(sctx, req, 0);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	locked = mutex_trylock(&ctrblk_lock);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
5838c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
5848c2ecf20Sopenharmony_ci		n = AES_BLOCK_SIZE;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		if (nbytes >= 2*AES_BLOCK_SIZE && locked)
5878c2ecf20Sopenharmony_ci			n = __ctrblk_init(ctrblk, walk.iv, nbytes);
5888c2ecf20Sopenharmony_ci		ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
5898c2ecf20Sopenharmony_ci		cpacf_kmctr(sctx->fc, sctx->key, walk.dst.virt.addr,
5908c2ecf20Sopenharmony_ci			    walk.src.virt.addr, n, ctrptr);
5918c2ecf20Sopenharmony_ci		if (ctrptr == ctrblk)
5928c2ecf20Sopenharmony_ci			memcpy(walk.iv, ctrptr + n - AES_BLOCK_SIZE,
5938c2ecf20Sopenharmony_ci			       AES_BLOCK_SIZE);
5948c2ecf20Sopenharmony_ci		crypto_inc(walk.iv, AES_BLOCK_SIZE);
5958c2ecf20Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes - n);
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci	if (locked)
5988c2ecf20Sopenharmony_ci		mutex_unlock(&ctrblk_lock);
5998c2ecf20Sopenharmony_ci	/*
6008c2ecf20Sopenharmony_ci	 * final block may be < AES_BLOCK_SIZE, copy only nbytes
6018c2ecf20Sopenharmony_ci	 */
6028c2ecf20Sopenharmony_ci	if (nbytes) {
6038c2ecf20Sopenharmony_ci		memset(buf, 0, AES_BLOCK_SIZE);
6048c2ecf20Sopenharmony_ci		memcpy(buf, walk.src.virt.addr, nbytes);
6058c2ecf20Sopenharmony_ci		cpacf_kmctr(sctx->fc, sctx->key, buf, buf,
6068c2ecf20Sopenharmony_ci			    AES_BLOCK_SIZE, walk.iv);
6078c2ecf20Sopenharmony_ci		memcpy(walk.dst.virt.addr, buf, nbytes);
6088c2ecf20Sopenharmony_ci		crypto_inc(walk.iv, AES_BLOCK_SIZE);
6098c2ecf20Sopenharmony_ci		ret = skcipher_walk_done(&walk, 0);
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return ret;
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic struct skcipher_alg ctr_aes_alg = {
6168c2ecf20Sopenharmony_ci	.base.cra_name		=	"ctr(aes)",
6178c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"ctr-aes-s390",
6188c2ecf20Sopenharmony_ci	.base.cra_priority	=	402,	/* ecb-aes-s390 + 1 */
6198c2ecf20Sopenharmony_ci	.base.cra_flags		=	CRYPTO_ALG_NEED_FALLBACK,
6208c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	1,
6218c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_aes_ctx),
6228c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
6238c2ecf20Sopenharmony_ci	.init			=	fallback_init_skcipher,
6248c2ecf20Sopenharmony_ci	.exit			=	fallback_exit_skcipher,
6258c2ecf20Sopenharmony_ci	.min_keysize		=	AES_MIN_KEY_SIZE,
6268c2ecf20Sopenharmony_ci	.max_keysize		=	AES_MAX_KEY_SIZE,
6278c2ecf20Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
6288c2ecf20Sopenharmony_ci	.setkey			=	ctr_aes_set_key,
6298c2ecf20Sopenharmony_ci	.encrypt		=	ctr_aes_crypt,
6308c2ecf20Sopenharmony_ci	.decrypt		=	ctr_aes_crypt,
6318c2ecf20Sopenharmony_ci	.chunksize		=	AES_BLOCK_SIZE,
6328c2ecf20Sopenharmony_ci};
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic int gcm_aes_setkey(struct crypto_aead *tfm, const u8 *key,
6358c2ecf20Sopenharmony_ci			  unsigned int keylen)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	struct s390_aes_ctx *ctx = crypto_aead_ctx(tfm);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	switch (keylen) {
6408c2ecf20Sopenharmony_ci	case AES_KEYSIZE_128:
6418c2ecf20Sopenharmony_ci		ctx->fc = CPACF_KMA_GCM_AES_128;
6428c2ecf20Sopenharmony_ci		break;
6438c2ecf20Sopenharmony_ci	case AES_KEYSIZE_192:
6448c2ecf20Sopenharmony_ci		ctx->fc = CPACF_KMA_GCM_AES_192;
6458c2ecf20Sopenharmony_ci		break;
6468c2ecf20Sopenharmony_ci	case AES_KEYSIZE_256:
6478c2ecf20Sopenharmony_ci		ctx->fc = CPACF_KMA_GCM_AES_256;
6488c2ecf20Sopenharmony_ci		break;
6498c2ecf20Sopenharmony_ci	default:
6508c2ecf20Sopenharmony_ci		return -EINVAL;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	memcpy(ctx->key, key, keylen);
6548c2ecf20Sopenharmony_ci	ctx->key_len = keylen;
6558c2ecf20Sopenharmony_ci	return 0;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic int gcm_aes_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	switch (authsize) {
6618c2ecf20Sopenharmony_ci	case 4:
6628c2ecf20Sopenharmony_ci	case 8:
6638c2ecf20Sopenharmony_ci	case 12:
6648c2ecf20Sopenharmony_ci	case 13:
6658c2ecf20Sopenharmony_ci	case 14:
6668c2ecf20Sopenharmony_ci	case 15:
6678c2ecf20Sopenharmony_ci	case 16:
6688c2ecf20Sopenharmony_ci		break;
6698c2ecf20Sopenharmony_ci	default:
6708c2ecf20Sopenharmony_ci		return -EINVAL;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	return 0;
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cistatic void gcm_walk_start(struct gcm_sg_walk *gw, struct scatterlist *sg,
6778c2ecf20Sopenharmony_ci			   unsigned int len)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	memset(gw, 0, sizeof(*gw));
6808c2ecf20Sopenharmony_ci	gw->walk_bytes_remain = len;
6818c2ecf20Sopenharmony_ci	scatterwalk_start(&gw->walk, sg);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic inline unsigned int _gcm_sg_clamp_and_map(struct gcm_sg_walk *gw)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	struct scatterlist *nextsg;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	gw->walk_bytes = scatterwalk_clamp(&gw->walk, gw->walk_bytes_remain);
6898c2ecf20Sopenharmony_ci	while (!gw->walk_bytes) {
6908c2ecf20Sopenharmony_ci		nextsg = sg_next(gw->walk.sg);
6918c2ecf20Sopenharmony_ci		if (!nextsg)
6928c2ecf20Sopenharmony_ci			return 0;
6938c2ecf20Sopenharmony_ci		scatterwalk_start(&gw->walk, nextsg);
6948c2ecf20Sopenharmony_ci		gw->walk_bytes = scatterwalk_clamp(&gw->walk,
6958c2ecf20Sopenharmony_ci						   gw->walk_bytes_remain);
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci	gw->walk_ptr = scatterwalk_map(&gw->walk);
6988c2ecf20Sopenharmony_ci	return gw->walk_bytes;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic inline void _gcm_sg_unmap_and_advance(struct gcm_sg_walk *gw,
7028c2ecf20Sopenharmony_ci					     unsigned int nbytes)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	gw->walk_bytes_remain -= nbytes;
7058c2ecf20Sopenharmony_ci	scatterwalk_unmap(gw->walk_ptr);
7068c2ecf20Sopenharmony_ci	scatterwalk_advance(&gw->walk, nbytes);
7078c2ecf20Sopenharmony_ci	scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain);
7088c2ecf20Sopenharmony_ci	gw->walk_ptr = NULL;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cistatic int gcm_in_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	int n;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (gw->buf_bytes && gw->buf_bytes >= minbytesneeded) {
7168c2ecf20Sopenharmony_ci		gw->ptr = gw->buf;
7178c2ecf20Sopenharmony_ci		gw->nbytes = gw->buf_bytes;
7188c2ecf20Sopenharmony_ci		goto out;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (gw->walk_bytes_remain == 0) {
7228c2ecf20Sopenharmony_ci		gw->ptr = NULL;
7238c2ecf20Sopenharmony_ci		gw->nbytes = 0;
7248c2ecf20Sopenharmony_ci		goto out;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (!_gcm_sg_clamp_and_map(gw)) {
7288c2ecf20Sopenharmony_ci		gw->ptr = NULL;
7298c2ecf20Sopenharmony_ci		gw->nbytes = 0;
7308c2ecf20Sopenharmony_ci		goto out;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	if (!gw->buf_bytes && gw->walk_bytes >= minbytesneeded) {
7348c2ecf20Sopenharmony_ci		gw->ptr = gw->walk_ptr;
7358c2ecf20Sopenharmony_ci		gw->nbytes = gw->walk_bytes;
7368c2ecf20Sopenharmony_ci		goto out;
7378c2ecf20Sopenharmony_ci	}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	while (1) {
7408c2ecf20Sopenharmony_ci		n = min(gw->walk_bytes, AES_BLOCK_SIZE - gw->buf_bytes);
7418c2ecf20Sopenharmony_ci		memcpy(gw->buf + gw->buf_bytes, gw->walk_ptr, n);
7428c2ecf20Sopenharmony_ci		gw->buf_bytes += n;
7438c2ecf20Sopenharmony_ci		_gcm_sg_unmap_and_advance(gw, n);
7448c2ecf20Sopenharmony_ci		if (gw->buf_bytes >= minbytesneeded) {
7458c2ecf20Sopenharmony_ci			gw->ptr = gw->buf;
7468c2ecf20Sopenharmony_ci			gw->nbytes = gw->buf_bytes;
7478c2ecf20Sopenharmony_ci			goto out;
7488c2ecf20Sopenharmony_ci		}
7498c2ecf20Sopenharmony_ci		if (!_gcm_sg_clamp_and_map(gw)) {
7508c2ecf20Sopenharmony_ci			gw->ptr = NULL;
7518c2ecf20Sopenharmony_ci			gw->nbytes = 0;
7528c2ecf20Sopenharmony_ci			goto out;
7538c2ecf20Sopenharmony_ci		}
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ciout:
7578c2ecf20Sopenharmony_ci	return gw->nbytes;
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cistatic int gcm_out_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci	if (gw->walk_bytes_remain == 0) {
7638c2ecf20Sopenharmony_ci		gw->ptr = NULL;
7648c2ecf20Sopenharmony_ci		gw->nbytes = 0;
7658c2ecf20Sopenharmony_ci		goto out;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (!_gcm_sg_clamp_and_map(gw)) {
7698c2ecf20Sopenharmony_ci		gw->ptr = NULL;
7708c2ecf20Sopenharmony_ci		gw->nbytes = 0;
7718c2ecf20Sopenharmony_ci		goto out;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (gw->walk_bytes >= minbytesneeded) {
7758c2ecf20Sopenharmony_ci		gw->ptr = gw->walk_ptr;
7768c2ecf20Sopenharmony_ci		gw->nbytes = gw->walk_bytes;
7778c2ecf20Sopenharmony_ci		goto out;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	scatterwalk_unmap(gw->walk_ptr);
7818c2ecf20Sopenharmony_ci	gw->walk_ptr = NULL;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	gw->ptr = gw->buf;
7848c2ecf20Sopenharmony_ci	gw->nbytes = sizeof(gw->buf);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ciout:
7878c2ecf20Sopenharmony_ci	return gw->nbytes;
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistatic int gcm_in_walk_done(struct gcm_sg_walk *gw, unsigned int bytesdone)
7918c2ecf20Sopenharmony_ci{
7928c2ecf20Sopenharmony_ci	if (gw->ptr == NULL)
7938c2ecf20Sopenharmony_ci		return 0;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (gw->ptr == gw->buf) {
7968c2ecf20Sopenharmony_ci		int n = gw->buf_bytes - bytesdone;
7978c2ecf20Sopenharmony_ci		if (n > 0) {
7988c2ecf20Sopenharmony_ci			memmove(gw->buf, gw->buf + bytesdone, n);
7998c2ecf20Sopenharmony_ci			gw->buf_bytes = n;
8008c2ecf20Sopenharmony_ci		} else
8018c2ecf20Sopenharmony_ci			gw->buf_bytes = 0;
8028c2ecf20Sopenharmony_ci	} else
8038c2ecf20Sopenharmony_ci		_gcm_sg_unmap_and_advance(gw, bytesdone);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	return bytesdone;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic int gcm_out_walk_done(struct gcm_sg_walk *gw, unsigned int bytesdone)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	int i, n;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (gw->ptr == NULL)
8138c2ecf20Sopenharmony_ci		return 0;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (gw->ptr == gw->buf) {
8168c2ecf20Sopenharmony_ci		for (i = 0; i < bytesdone; i += n) {
8178c2ecf20Sopenharmony_ci			if (!_gcm_sg_clamp_and_map(gw))
8188c2ecf20Sopenharmony_ci				return i;
8198c2ecf20Sopenharmony_ci			n = min(gw->walk_bytes, bytesdone - i);
8208c2ecf20Sopenharmony_ci			memcpy(gw->walk_ptr, gw->buf + i, n);
8218c2ecf20Sopenharmony_ci			_gcm_sg_unmap_and_advance(gw, n);
8228c2ecf20Sopenharmony_ci		}
8238c2ecf20Sopenharmony_ci	} else
8248c2ecf20Sopenharmony_ci		_gcm_sg_unmap_and_advance(gw, bytesdone);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	return bytesdone;
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic int gcm_aes_crypt(struct aead_request *req, unsigned int flags)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
8328c2ecf20Sopenharmony_ci	struct s390_aes_ctx *ctx = crypto_aead_ctx(tfm);
8338c2ecf20Sopenharmony_ci	unsigned int ivsize = crypto_aead_ivsize(tfm);
8348c2ecf20Sopenharmony_ci	unsigned int taglen = crypto_aead_authsize(tfm);
8358c2ecf20Sopenharmony_ci	unsigned int aadlen = req->assoclen;
8368c2ecf20Sopenharmony_ci	unsigned int pclen = req->cryptlen;
8378c2ecf20Sopenharmony_ci	int ret = 0;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	unsigned int n, len, in_bytes, out_bytes,
8408c2ecf20Sopenharmony_ci		     min_bytes, bytes, aad_bytes, pc_bytes;
8418c2ecf20Sopenharmony_ci	struct gcm_sg_walk gw_in, gw_out;
8428c2ecf20Sopenharmony_ci	u8 tag[GHASH_DIGEST_SIZE];
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	struct {
8458c2ecf20Sopenharmony_ci		u32 _[3];		/* reserved */
8468c2ecf20Sopenharmony_ci		u32 cv;			/* Counter Value */
8478c2ecf20Sopenharmony_ci		u8 t[GHASH_DIGEST_SIZE];/* Tag */
8488c2ecf20Sopenharmony_ci		u8 h[AES_BLOCK_SIZE];	/* Hash-subkey */
8498c2ecf20Sopenharmony_ci		u64 taadl;		/* Total AAD Length */
8508c2ecf20Sopenharmony_ci		u64 tpcl;		/* Total Plain-/Cipher-text Length */
8518c2ecf20Sopenharmony_ci		u8 j0[GHASH_BLOCK_SIZE];/* initial counter value */
8528c2ecf20Sopenharmony_ci		u8 k[AES_MAX_KEY_SIZE];	/* Key */
8538c2ecf20Sopenharmony_ci	} param;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	/*
8568c2ecf20Sopenharmony_ci	 * encrypt
8578c2ecf20Sopenharmony_ci	 *   req->src: aad||plaintext
8588c2ecf20Sopenharmony_ci	 *   req->dst: aad||ciphertext||tag
8598c2ecf20Sopenharmony_ci	 * decrypt
8608c2ecf20Sopenharmony_ci	 *   req->src: aad||ciphertext||tag
8618c2ecf20Sopenharmony_ci	 *   req->dst: aad||plaintext, return 0 or -EBADMSG
8628c2ecf20Sopenharmony_ci	 * aad, plaintext and ciphertext may be empty.
8638c2ecf20Sopenharmony_ci	 */
8648c2ecf20Sopenharmony_ci	if (flags & CPACF_DECRYPT)
8658c2ecf20Sopenharmony_ci		pclen -= taglen;
8668c2ecf20Sopenharmony_ci	len = aadlen + pclen;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	memset(&param, 0, sizeof(param));
8698c2ecf20Sopenharmony_ci	param.cv = 1;
8708c2ecf20Sopenharmony_ci	param.taadl = aadlen * 8;
8718c2ecf20Sopenharmony_ci	param.tpcl = pclen * 8;
8728c2ecf20Sopenharmony_ci	memcpy(param.j0, req->iv, ivsize);
8738c2ecf20Sopenharmony_ci	*(u32 *)(param.j0 + ivsize) = 1;
8748c2ecf20Sopenharmony_ci	memcpy(param.k, ctx->key, ctx->key_len);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	gcm_walk_start(&gw_in, req->src, len);
8778c2ecf20Sopenharmony_ci	gcm_walk_start(&gw_out, req->dst, len);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	do {
8808c2ecf20Sopenharmony_ci		min_bytes = min_t(unsigned int,
8818c2ecf20Sopenharmony_ci				  aadlen > 0 ? aadlen : pclen, AES_BLOCK_SIZE);
8828c2ecf20Sopenharmony_ci		in_bytes = gcm_in_walk_go(&gw_in, min_bytes);
8838c2ecf20Sopenharmony_ci		out_bytes = gcm_out_walk_go(&gw_out, min_bytes);
8848c2ecf20Sopenharmony_ci		bytes = min(in_bytes, out_bytes);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		if (aadlen + pclen <= bytes) {
8878c2ecf20Sopenharmony_ci			aad_bytes = aadlen;
8888c2ecf20Sopenharmony_ci			pc_bytes = pclen;
8898c2ecf20Sopenharmony_ci			flags |= CPACF_KMA_LAAD | CPACF_KMA_LPC;
8908c2ecf20Sopenharmony_ci		} else {
8918c2ecf20Sopenharmony_ci			if (aadlen <= bytes) {
8928c2ecf20Sopenharmony_ci				aad_bytes = aadlen;
8938c2ecf20Sopenharmony_ci				pc_bytes = (bytes - aadlen) &
8948c2ecf20Sopenharmony_ci					   ~(AES_BLOCK_SIZE - 1);
8958c2ecf20Sopenharmony_ci				flags |= CPACF_KMA_LAAD;
8968c2ecf20Sopenharmony_ci			} else {
8978c2ecf20Sopenharmony_ci				aad_bytes = bytes & ~(AES_BLOCK_SIZE - 1);
8988c2ecf20Sopenharmony_ci				pc_bytes = 0;
8998c2ecf20Sopenharmony_ci			}
9008c2ecf20Sopenharmony_ci		}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci		if (aad_bytes > 0)
9038c2ecf20Sopenharmony_ci			memcpy(gw_out.ptr, gw_in.ptr, aad_bytes);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci		cpacf_kma(ctx->fc | flags, &param,
9068c2ecf20Sopenharmony_ci			  gw_out.ptr + aad_bytes,
9078c2ecf20Sopenharmony_ci			  gw_in.ptr + aad_bytes, pc_bytes,
9088c2ecf20Sopenharmony_ci			  gw_in.ptr, aad_bytes);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci		n = aad_bytes + pc_bytes;
9118c2ecf20Sopenharmony_ci		if (gcm_in_walk_done(&gw_in, n) != n)
9128c2ecf20Sopenharmony_ci			return -ENOMEM;
9138c2ecf20Sopenharmony_ci		if (gcm_out_walk_done(&gw_out, n) != n)
9148c2ecf20Sopenharmony_ci			return -ENOMEM;
9158c2ecf20Sopenharmony_ci		aadlen -= aad_bytes;
9168c2ecf20Sopenharmony_ci		pclen -= pc_bytes;
9178c2ecf20Sopenharmony_ci	} while (aadlen + pclen > 0);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	if (flags & CPACF_DECRYPT) {
9208c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(tag, req->src, len, taglen, 0);
9218c2ecf20Sopenharmony_ci		if (crypto_memneq(tag, param.t, taglen))
9228c2ecf20Sopenharmony_ci			ret = -EBADMSG;
9238c2ecf20Sopenharmony_ci	} else
9248c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(param.t, req->dst, len, taglen, 1);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	memzero_explicit(&param, sizeof(param));
9278c2ecf20Sopenharmony_ci	return ret;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic int gcm_aes_encrypt(struct aead_request *req)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	return gcm_aes_crypt(req, CPACF_ENCRYPT);
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic int gcm_aes_decrypt(struct aead_request *req)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	return gcm_aes_crypt(req, CPACF_DECRYPT);
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic struct aead_alg gcm_aes_aead = {
9418c2ecf20Sopenharmony_ci	.setkey			= gcm_aes_setkey,
9428c2ecf20Sopenharmony_ci	.setauthsize		= gcm_aes_setauthsize,
9438c2ecf20Sopenharmony_ci	.encrypt		= gcm_aes_encrypt,
9448c2ecf20Sopenharmony_ci	.decrypt		= gcm_aes_decrypt,
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	.ivsize			= GHASH_BLOCK_SIZE - sizeof(u32),
9478c2ecf20Sopenharmony_ci	.maxauthsize		= GHASH_DIGEST_SIZE,
9488c2ecf20Sopenharmony_ci	.chunksize		= AES_BLOCK_SIZE,
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	.base			= {
9518c2ecf20Sopenharmony_ci		.cra_blocksize		= 1,
9528c2ecf20Sopenharmony_ci		.cra_ctxsize		= sizeof(struct s390_aes_ctx),
9538c2ecf20Sopenharmony_ci		.cra_priority		= 900,
9548c2ecf20Sopenharmony_ci		.cra_name		= "gcm(aes)",
9558c2ecf20Sopenharmony_ci		.cra_driver_name	= "gcm-aes-s390",
9568c2ecf20Sopenharmony_ci		.cra_module		= THIS_MODULE,
9578c2ecf20Sopenharmony_ci	},
9588c2ecf20Sopenharmony_ci};
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic struct crypto_alg *aes_s390_alg;
9618c2ecf20Sopenharmony_cistatic struct skcipher_alg *aes_s390_skcipher_algs[4];
9628c2ecf20Sopenharmony_cistatic int aes_s390_skciphers_num;
9638c2ecf20Sopenharmony_cistatic struct aead_alg *aes_s390_aead_alg;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic int aes_s390_register_skcipher(struct skcipher_alg *alg)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	int ret;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	ret = crypto_register_skcipher(alg);
9708c2ecf20Sopenharmony_ci	if (!ret)
9718c2ecf20Sopenharmony_ci		aes_s390_skcipher_algs[aes_s390_skciphers_num++] = alg;
9728c2ecf20Sopenharmony_ci	return ret;
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_cistatic void aes_s390_fini(void)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci	if (aes_s390_alg)
9788c2ecf20Sopenharmony_ci		crypto_unregister_alg(aes_s390_alg);
9798c2ecf20Sopenharmony_ci	while (aes_s390_skciphers_num--)
9808c2ecf20Sopenharmony_ci		crypto_unregister_skcipher(aes_s390_skcipher_algs[aes_s390_skciphers_num]);
9818c2ecf20Sopenharmony_ci	if (ctrblk)
9828c2ecf20Sopenharmony_ci		free_page((unsigned long) ctrblk);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	if (aes_s390_aead_alg)
9858c2ecf20Sopenharmony_ci		crypto_unregister_aead(aes_s390_aead_alg);
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_cistatic int __init aes_s390_init(void)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	int ret;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	/* Query available functions for KM, KMC, KMCTR and KMA */
9938c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KM, &km_functions);
9948c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KMC, &kmc_functions);
9958c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KMCTR, &kmctr_functions);
9968c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KMA, &kma_functions);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	if (cpacf_test_func(&km_functions, CPACF_KM_AES_128) ||
9998c2ecf20Sopenharmony_ci	    cpacf_test_func(&km_functions, CPACF_KM_AES_192) ||
10008c2ecf20Sopenharmony_ci	    cpacf_test_func(&km_functions, CPACF_KM_AES_256)) {
10018c2ecf20Sopenharmony_ci		ret = crypto_register_alg(&aes_alg);
10028c2ecf20Sopenharmony_ci		if (ret)
10038c2ecf20Sopenharmony_ci			goto out_err;
10048c2ecf20Sopenharmony_ci		aes_s390_alg = &aes_alg;
10058c2ecf20Sopenharmony_ci		ret = aes_s390_register_skcipher(&ecb_aes_alg);
10068c2ecf20Sopenharmony_ci		if (ret)
10078c2ecf20Sopenharmony_ci			goto out_err;
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	if (cpacf_test_func(&kmc_functions, CPACF_KMC_AES_128) ||
10118c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmc_functions, CPACF_KMC_AES_192) ||
10128c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmc_functions, CPACF_KMC_AES_256)) {
10138c2ecf20Sopenharmony_ci		ret = aes_s390_register_skcipher(&cbc_aes_alg);
10148c2ecf20Sopenharmony_ci		if (ret)
10158c2ecf20Sopenharmony_ci			goto out_err;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	if (cpacf_test_func(&km_functions, CPACF_KM_XTS_128) ||
10198c2ecf20Sopenharmony_ci	    cpacf_test_func(&km_functions, CPACF_KM_XTS_256)) {
10208c2ecf20Sopenharmony_ci		ret = aes_s390_register_skcipher(&xts_aes_alg);
10218c2ecf20Sopenharmony_ci		if (ret)
10228c2ecf20Sopenharmony_ci			goto out_err;
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_AES_128) ||
10268c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_AES_192) ||
10278c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_AES_256)) {
10288c2ecf20Sopenharmony_ci		ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
10298c2ecf20Sopenharmony_ci		if (!ctrblk) {
10308c2ecf20Sopenharmony_ci			ret = -ENOMEM;
10318c2ecf20Sopenharmony_ci			goto out_err;
10328c2ecf20Sopenharmony_ci		}
10338c2ecf20Sopenharmony_ci		ret = aes_s390_register_skcipher(&ctr_aes_alg);
10348c2ecf20Sopenharmony_ci		if (ret)
10358c2ecf20Sopenharmony_ci			goto out_err;
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	if (cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_128) ||
10398c2ecf20Sopenharmony_ci	    cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_192) ||
10408c2ecf20Sopenharmony_ci	    cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_256)) {
10418c2ecf20Sopenharmony_ci		ret = crypto_register_aead(&gcm_aes_aead);
10428c2ecf20Sopenharmony_ci		if (ret)
10438c2ecf20Sopenharmony_ci			goto out_err;
10448c2ecf20Sopenharmony_ci		aes_s390_aead_alg = &gcm_aes_aead;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	return 0;
10488c2ecf20Sopenharmony_ciout_err:
10498c2ecf20Sopenharmony_ci	aes_s390_fini();
10508c2ecf20Sopenharmony_ci	return ret;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cimodule_cpu_feature_match(MSA, aes_s390_init);
10548c2ecf20Sopenharmony_cimodule_exit(aes_s390_fini);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes-all");
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
10598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1060