18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Glue code for AES implementation for SPE instructions (PPC)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on generic implementation. The assembler module takes care
68c2ecf20Sopenharmony_ci * about the SPE registers so it can run from interrupt context.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <crypto/aes.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/crypto.h>
178c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
188c2ecf20Sopenharmony_ci#include <asm/switch_to.h>
198c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
208c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
218c2ecf20Sopenharmony_ci#include <crypto/xts.h>
228c2ecf20Sopenharmony_ci#include <crypto/gf128mul.h>
238c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * MAX_BYTES defines the number of bytes that are allowed to be processed
278c2ecf20Sopenharmony_ci * between preempt_disable() and preempt_enable(). e500 cores can issue two
288c2ecf20Sopenharmony_ci * instructions per clock cycle using one 32/64 bit unit (SU1) and one 32
298c2ecf20Sopenharmony_ci * bit unit (SU2). One of these can be a memory access that is executed via
308c2ecf20Sopenharmony_ci * a single load and store unit (LSU). XTS-AES-256 takes ~780 operations per
318c2ecf20Sopenharmony_ci * 16 byte block block or 25 cycles per byte. Thus 768 bytes of input data
328c2ecf20Sopenharmony_ci * will need an estimated maximum of 20,000 cycles. Headroom for cache misses
338c2ecf20Sopenharmony_ci * included. Even with the low end model clocked at 667 MHz this equals to a
348c2ecf20Sopenharmony_ci * critical time window of less than 30us. The value has been chosen to
358c2ecf20Sopenharmony_ci * process a 512 byte disk block in one or a large 1400 bytes IPsec network
368c2ecf20Sopenharmony_ci * packet in two runs.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci#define MAX_BYTES 768
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct ppc_aes_ctx {
428c2ecf20Sopenharmony_ci	u32 key_enc[AES_MAX_KEYLENGTH_U32];
438c2ecf20Sopenharmony_ci	u32 key_dec[AES_MAX_KEYLENGTH_U32];
448c2ecf20Sopenharmony_ci	u32 rounds;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct ppc_xts_ctx {
488c2ecf20Sopenharmony_ci	u32 key_enc[AES_MAX_KEYLENGTH_U32];
498c2ecf20Sopenharmony_ci	u32 key_dec[AES_MAX_KEYLENGTH_U32];
508c2ecf20Sopenharmony_ci	u32 key_twk[AES_MAX_KEYLENGTH_U32];
518c2ecf20Sopenharmony_ci	u32 rounds;
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciextern void ppc_encrypt_aes(u8 *out, const u8 *in, u32 *key_enc, u32 rounds);
558c2ecf20Sopenharmony_ciextern void ppc_decrypt_aes(u8 *out, const u8 *in, u32 *key_dec, u32 rounds);
568c2ecf20Sopenharmony_ciextern void ppc_encrypt_ecb(u8 *out, const u8 *in, u32 *key_enc, u32 rounds,
578c2ecf20Sopenharmony_ci			    u32 bytes);
588c2ecf20Sopenharmony_ciextern void ppc_decrypt_ecb(u8 *out, const u8 *in, u32 *key_dec, u32 rounds,
598c2ecf20Sopenharmony_ci			    u32 bytes);
608c2ecf20Sopenharmony_ciextern void ppc_encrypt_cbc(u8 *out, const u8 *in, u32 *key_enc, u32 rounds,
618c2ecf20Sopenharmony_ci			    u32 bytes, u8 *iv);
628c2ecf20Sopenharmony_ciextern void ppc_decrypt_cbc(u8 *out, const u8 *in, u32 *key_dec, u32 rounds,
638c2ecf20Sopenharmony_ci			    u32 bytes, u8 *iv);
648c2ecf20Sopenharmony_ciextern void ppc_crypt_ctr  (u8 *out, const u8 *in, u32 *key_enc, u32 rounds,
658c2ecf20Sopenharmony_ci			    u32 bytes, u8 *iv);
668c2ecf20Sopenharmony_ciextern void ppc_encrypt_xts(u8 *out, const u8 *in, u32 *key_enc, u32 rounds,
678c2ecf20Sopenharmony_ci			    u32 bytes, u8 *iv, u32 *key_twk);
688c2ecf20Sopenharmony_ciextern void ppc_decrypt_xts(u8 *out, const u8 *in, u32 *key_dec, u32 rounds,
698c2ecf20Sopenharmony_ci			    u32 bytes, u8 *iv, u32 *key_twk);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciextern void ppc_expand_key_128(u32 *key_enc, const u8 *key);
728c2ecf20Sopenharmony_ciextern void ppc_expand_key_192(u32 *key_enc, const u8 *key);
738c2ecf20Sopenharmony_ciextern void ppc_expand_key_256(u32 *key_enc, const u8 *key);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciextern void ppc_generate_decrypt_key(u32 *key_dec,u32 *key_enc,
768c2ecf20Sopenharmony_ci				     unsigned int key_len);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic void spe_begin(void)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	/* disable preemption and save users SPE registers if required */
818c2ecf20Sopenharmony_ci	preempt_disable();
828c2ecf20Sopenharmony_ci	enable_kernel_spe();
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void spe_end(void)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	disable_kernel_spe();
888c2ecf20Sopenharmony_ci	/* reenable preemption */
898c2ecf20Sopenharmony_ci	preempt_enable();
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int ppc_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
938c2ecf20Sopenharmony_ci		unsigned int key_len)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	switch (key_len) {
988c2ecf20Sopenharmony_ci	case AES_KEYSIZE_128:
998c2ecf20Sopenharmony_ci		ctx->rounds = 4;
1008c2ecf20Sopenharmony_ci		ppc_expand_key_128(ctx->key_enc, in_key);
1018c2ecf20Sopenharmony_ci		break;
1028c2ecf20Sopenharmony_ci	case AES_KEYSIZE_192:
1038c2ecf20Sopenharmony_ci		ctx->rounds = 5;
1048c2ecf20Sopenharmony_ci		ppc_expand_key_192(ctx->key_enc, in_key);
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci	case AES_KEYSIZE_256:
1078c2ecf20Sopenharmony_ci		ctx->rounds = 6;
1088c2ecf20Sopenharmony_ci		ppc_expand_key_256(ctx->key_enc, in_key);
1098c2ecf20Sopenharmony_ci		break;
1108c2ecf20Sopenharmony_ci	default:
1118c2ecf20Sopenharmony_ci		return -EINVAL;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int ppc_aes_setkey_skcipher(struct crypto_skcipher *tfm,
1208c2ecf20Sopenharmony_ci				   const u8 *in_key, unsigned int key_len)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	return ppc_aes_setkey(crypto_skcipher_tfm(tfm), in_key, key_len);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int ppc_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
1268c2ecf20Sopenharmony_ci		   unsigned int key_len)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
1298c2ecf20Sopenharmony_ci	int err;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	err = xts_verify_key(tfm, in_key, key_len);
1328c2ecf20Sopenharmony_ci	if (err)
1338c2ecf20Sopenharmony_ci		return err;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	key_len >>= 1;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	switch (key_len) {
1388c2ecf20Sopenharmony_ci	case AES_KEYSIZE_128:
1398c2ecf20Sopenharmony_ci		ctx->rounds = 4;
1408c2ecf20Sopenharmony_ci		ppc_expand_key_128(ctx->key_enc, in_key);
1418c2ecf20Sopenharmony_ci		ppc_expand_key_128(ctx->key_twk, in_key + AES_KEYSIZE_128);
1428c2ecf20Sopenharmony_ci		break;
1438c2ecf20Sopenharmony_ci	case AES_KEYSIZE_192:
1448c2ecf20Sopenharmony_ci		ctx->rounds = 5;
1458c2ecf20Sopenharmony_ci		ppc_expand_key_192(ctx->key_enc, in_key);
1468c2ecf20Sopenharmony_ci		ppc_expand_key_192(ctx->key_twk, in_key + AES_KEYSIZE_192);
1478c2ecf20Sopenharmony_ci		break;
1488c2ecf20Sopenharmony_ci	case AES_KEYSIZE_256:
1498c2ecf20Sopenharmony_ci		ctx->rounds = 6;
1508c2ecf20Sopenharmony_ci		ppc_expand_key_256(ctx->key_enc, in_key);
1518c2ecf20Sopenharmony_ci		ppc_expand_key_256(ctx->key_twk, in_key + AES_KEYSIZE_256);
1528c2ecf20Sopenharmony_ci		break;
1538c2ecf20Sopenharmony_ci	default:
1548c2ecf20Sopenharmony_ci		return -EINVAL;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return 0;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic void ppc_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	spe_begin();
1678c2ecf20Sopenharmony_ci	ppc_encrypt_aes(out, in, ctx->key_enc, ctx->rounds);
1688c2ecf20Sopenharmony_ci	spe_end();
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void ppc_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	spe_begin();
1768c2ecf20Sopenharmony_ci	ppc_decrypt_aes(out, in, ctx->key_dec, ctx->rounds);
1778c2ecf20Sopenharmony_ci	spe_end();
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int ppc_ecb_crypt(struct skcipher_request *req, bool enc)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1838c2ecf20Sopenharmony_ci	struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
1848c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
1858c2ecf20Sopenharmony_ci	unsigned int nbytes;
1868c2ecf20Sopenharmony_ci	int err;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
1918c2ecf20Sopenharmony_ci		nbytes = min_t(unsigned int, nbytes, MAX_BYTES);
1928c2ecf20Sopenharmony_ci		nbytes = round_down(nbytes, AES_BLOCK_SIZE);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		spe_begin();
1958c2ecf20Sopenharmony_ci		if (enc)
1968c2ecf20Sopenharmony_ci			ppc_encrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr,
1978c2ecf20Sopenharmony_ci					ctx->key_enc, ctx->rounds, nbytes);
1988c2ecf20Sopenharmony_ci		else
1998c2ecf20Sopenharmony_ci			ppc_decrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr,
2008c2ecf20Sopenharmony_ci					ctx->key_dec, ctx->rounds, nbytes);
2018c2ecf20Sopenharmony_ci		spe_end();
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return err;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic int ppc_ecb_encrypt(struct skcipher_request *req)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	return ppc_ecb_crypt(req, true);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int ppc_ecb_decrypt(struct skcipher_request *req)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	return ppc_ecb_crypt(req, false);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int ppc_cbc_crypt(struct skcipher_request *req, bool enc)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2228c2ecf20Sopenharmony_ci	struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
2238c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2248c2ecf20Sopenharmony_ci	unsigned int nbytes;
2258c2ecf20Sopenharmony_ci	int err;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
2308c2ecf20Sopenharmony_ci		nbytes = min_t(unsigned int, nbytes, MAX_BYTES);
2318c2ecf20Sopenharmony_ci		nbytes = round_down(nbytes, AES_BLOCK_SIZE);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		spe_begin();
2348c2ecf20Sopenharmony_ci		if (enc)
2358c2ecf20Sopenharmony_ci			ppc_encrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr,
2368c2ecf20Sopenharmony_ci					ctx->key_enc, ctx->rounds, nbytes,
2378c2ecf20Sopenharmony_ci					walk.iv);
2388c2ecf20Sopenharmony_ci		else
2398c2ecf20Sopenharmony_ci			ppc_decrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr,
2408c2ecf20Sopenharmony_ci					ctx->key_dec, ctx->rounds, nbytes,
2418c2ecf20Sopenharmony_ci					walk.iv);
2428c2ecf20Sopenharmony_ci		spe_end();
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return err;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic int ppc_cbc_encrypt(struct skcipher_request *req)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	return ppc_cbc_crypt(req, true);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int ppc_cbc_decrypt(struct skcipher_request *req)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	return ppc_cbc_crypt(req, false);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int ppc_ctr_crypt(struct skcipher_request *req)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2638c2ecf20Sopenharmony_ci	struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
2648c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2658c2ecf20Sopenharmony_ci	unsigned int nbytes;
2668c2ecf20Sopenharmony_ci	int err;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
2718c2ecf20Sopenharmony_ci		nbytes = min_t(unsigned int, nbytes, MAX_BYTES);
2728c2ecf20Sopenharmony_ci		if (nbytes < walk.total)
2738c2ecf20Sopenharmony_ci			nbytes = round_down(nbytes, AES_BLOCK_SIZE);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		spe_begin();
2768c2ecf20Sopenharmony_ci		ppc_crypt_ctr(walk.dst.virt.addr, walk.src.virt.addr,
2778c2ecf20Sopenharmony_ci			      ctx->key_enc, ctx->rounds, nbytes, walk.iv);
2788c2ecf20Sopenharmony_ci		spe_end();
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return err;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic int ppc_xts_crypt(struct skcipher_request *req, bool enc)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2898c2ecf20Sopenharmony_ci	struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
2908c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2918c2ecf20Sopenharmony_ci	unsigned int nbytes;
2928c2ecf20Sopenharmony_ci	int err;
2938c2ecf20Sopenharmony_ci	u32 *twk;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
2968c2ecf20Sopenharmony_ci	twk = ctx->key_twk;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
2998c2ecf20Sopenharmony_ci		nbytes = min_t(unsigned int, nbytes, MAX_BYTES);
3008c2ecf20Sopenharmony_ci		nbytes = round_down(nbytes, AES_BLOCK_SIZE);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		spe_begin();
3038c2ecf20Sopenharmony_ci		if (enc)
3048c2ecf20Sopenharmony_ci			ppc_encrypt_xts(walk.dst.virt.addr, walk.src.virt.addr,
3058c2ecf20Sopenharmony_ci					ctx->key_enc, ctx->rounds, nbytes,
3068c2ecf20Sopenharmony_ci					walk.iv, twk);
3078c2ecf20Sopenharmony_ci		else
3088c2ecf20Sopenharmony_ci			ppc_decrypt_xts(walk.dst.virt.addr, walk.src.virt.addr,
3098c2ecf20Sopenharmony_ci					ctx->key_dec, ctx->rounds, nbytes,
3108c2ecf20Sopenharmony_ci					walk.iv, twk);
3118c2ecf20Sopenharmony_ci		spe_end();
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		twk = NULL;
3148c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return err;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int ppc_xts_encrypt(struct skcipher_request *req)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
3238c2ecf20Sopenharmony_ci	struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
3248c2ecf20Sopenharmony_ci	int tail = req->cryptlen % AES_BLOCK_SIZE;
3258c2ecf20Sopenharmony_ci	int offset = req->cryptlen - tail - AES_BLOCK_SIZE;
3268c2ecf20Sopenharmony_ci	struct skcipher_request subreq;
3278c2ecf20Sopenharmony_ci	u8 b[2][AES_BLOCK_SIZE];
3288c2ecf20Sopenharmony_ci	int err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (req->cryptlen < AES_BLOCK_SIZE)
3318c2ecf20Sopenharmony_ci		return -EINVAL;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (tail) {
3348c2ecf20Sopenharmony_ci		subreq = *req;
3358c2ecf20Sopenharmony_ci		skcipher_request_set_crypt(&subreq, req->src, req->dst,
3368c2ecf20Sopenharmony_ci					   req->cryptlen - tail, req->iv);
3378c2ecf20Sopenharmony_ci		req = &subreq;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	err = ppc_xts_crypt(req, true);
3418c2ecf20Sopenharmony_ci	if (err || !tail)
3428c2ecf20Sopenharmony_ci		return err;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE, 0);
3458c2ecf20Sopenharmony_ci	memcpy(b[1], b[0], tail);
3468c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(b[0], req->src, offset + AES_BLOCK_SIZE, tail, 0);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	spe_begin();
3498c2ecf20Sopenharmony_ci	ppc_encrypt_xts(b[0], b[0], ctx->key_enc, ctx->rounds, AES_BLOCK_SIZE,
3508c2ecf20Sopenharmony_ci			req->iv, NULL);
3518c2ecf20Sopenharmony_ci	spe_end();
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE + tail, 1);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int ppc_xts_decrypt(struct skcipher_request *req)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
3618c2ecf20Sopenharmony_ci	struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
3628c2ecf20Sopenharmony_ci	int tail = req->cryptlen % AES_BLOCK_SIZE;
3638c2ecf20Sopenharmony_ci	int offset = req->cryptlen - tail - AES_BLOCK_SIZE;
3648c2ecf20Sopenharmony_ci	struct skcipher_request subreq;
3658c2ecf20Sopenharmony_ci	u8 b[3][AES_BLOCK_SIZE];
3668c2ecf20Sopenharmony_ci	le128 twk;
3678c2ecf20Sopenharmony_ci	int err;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (req->cryptlen < AES_BLOCK_SIZE)
3708c2ecf20Sopenharmony_ci		return -EINVAL;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (tail) {
3738c2ecf20Sopenharmony_ci		subreq = *req;
3748c2ecf20Sopenharmony_ci		skcipher_request_set_crypt(&subreq, req->src, req->dst,
3758c2ecf20Sopenharmony_ci					   offset, req->iv);
3768c2ecf20Sopenharmony_ci		req = &subreq;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	err = ppc_xts_crypt(req, false);
3808c2ecf20Sopenharmony_ci	if (err || !tail)
3818c2ecf20Sopenharmony_ci		return err;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(b[1], req->src, offset, AES_BLOCK_SIZE + tail, 0);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	spe_begin();
3868c2ecf20Sopenharmony_ci	if (!offset)
3878c2ecf20Sopenharmony_ci		ppc_encrypt_ecb(req->iv, req->iv, ctx->key_twk, ctx->rounds,
3888c2ecf20Sopenharmony_ci				AES_BLOCK_SIZE);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	gf128mul_x_ble(&twk, (le128 *)req->iv);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	ppc_decrypt_xts(b[1], b[1], ctx->key_dec, ctx->rounds, AES_BLOCK_SIZE,
3938c2ecf20Sopenharmony_ci			(u8 *)&twk, NULL);
3948c2ecf20Sopenharmony_ci	memcpy(b[0], b[2], tail);
3958c2ecf20Sopenharmony_ci	memcpy(b[0] + tail, b[1] + tail, AES_BLOCK_SIZE - tail);
3968c2ecf20Sopenharmony_ci	ppc_decrypt_xts(b[0], b[0], ctx->key_dec, ctx->rounds, AES_BLOCK_SIZE,
3978c2ecf20Sopenharmony_ci			req->iv, NULL);
3988c2ecf20Sopenharmony_ci	spe_end();
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE + tail, 1);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return 0;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci/*
4068c2ecf20Sopenharmony_ci * Algorithm definitions. Disabling alignment (cra_alignmask=0) was chosen
4078c2ecf20Sopenharmony_ci * because the e500 platform can handle unaligned reads/writes very efficently.
4088c2ecf20Sopenharmony_ci * This improves IPsec thoughput by another few percent. Additionally we assume
4098c2ecf20Sopenharmony_ci * that AES context is always aligned to at least 8 bytes because it is created
4108c2ecf20Sopenharmony_ci * with kmalloc() in the crypto infrastructure
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic struct crypto_alg aes_cipher_alg = {
4148c2ecf20Sopenharmony_ci	.cra_name		=	"aes",
4158c2ecf20Sopenharmony_ci	.cra_driver_name	=	"aes-ppc-spe",
4168c2ecf20Sopenharmony_ci	.cra_priority		=	300,
4178c2ecf20Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
4188c2ecf20Sopenharmony_ci	.cra_blocksize		=	AES_BLOCK_SIZE,
4198c2ecf20Sopenharmony_ci	.cra_ctxsize		=	sizeof(struct ppc_aes_ctx),
4208c2ecf20Sopenharmony_ci	.cra_alignmask		=	0,
4218c2ecf20Sopenharmony_ci	.cra_module		=	THIS_MODULE,
4228c2ecf20Sopenharmony_ci	.cra_u			=	{
4238c2ecf20Sopenharmony_ci		.cipher = {
4248c2ecf20Sopenharmony_ci			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
4258c2ecf20Sopenharmony_ci			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
4268c2ecf20Sopenharmony_ci			.cia_setkey		=	ppc_aes_setkey,
4278c2ecf20Sopenharmony_ci			.cia_encrypt		=	ppc_aes_encrypt,
4288c2ecf20Sopenharmony_ci			.cia_decrypt		=	ppc_aes_decrypt
4298c2ecf20Sopenharmony_ci		}
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic struct skcipher_alg aes_skcipher_algs[] = {
4348c2ecf20Sopenharmony_ci	{
4358c2ecf20Sopenharmony_ci		.base.cra_name		=	"ecb(aes)",
4368c2ecf20Sopenharmony_ci		.base.cra_driver_name	=	"ecb-ppc-spe",
4378c2ecf20Sopenharmony_ci		.base.cra_priority	=	300,
4388c2ecf20Sopenharmony_ci		.base.cra_blocksize	=	AES_BLOCK_SIZE,
4398c2ecf20Sopenharmony_ci		.base.cra_ctxsize	=	sizeof(struct ppc_aes_ctx),
4408c2ecf20Sopenharmony_ci		.base.cra_module	=	THIS_MODULE,
4418c2ecf20Sopenharmony_ci		.min_keysize		=	AES_MIN_KEY_SIZE,
4428c2ecf20Sopenharmony_ci		.max_keysize		=	AES_MAX_KEY_SIZE,
4438c2ecf20Sopenharmony_ci		.setkey			=	ppc_aes_setkey_skcipher,
4448c2ecf20Sopenharmony_ci		.encrypt		=	ppc_ecb_encrypt,
4458c2ecf20Sopenharmony_ci		.decrypt		=	ppc_ecb_decrypt,
4468c2ecf20Sopenharmony_ci	}, {
4478c2ecf20Sopenharmony_ci		.base.cra_name		=	"cbc(aes)",
4488c2ecf20Sopenharmony_ci		.base.cra_driver_name	=	"cbc-ppc-spe",
4498c2ecf20Sopenharmony_ci		.base.cra_priority	=	300,
4508c2ecf20Sopenharmony_ci		.base.cra_blocksize	=	AES_BLOCK_SIZE,
4518c2ecf20Sopenharmony_ci		.base.cra_ctxsize	=	sizeof(struct ppc_aes_ctx),
4528c2ecf20Sopenharmony_ci		.base.cra_module	=	THIS_MODULE,
4538c2ecf20Sopenharmony_ci		.min_keysize		=	AES_MIN_KEY_SIZE,
4548c2ecf20Sopenharmony_ci		.max_keysize		=	AES_MAX_KEY_SIZE,
4558c2ecf20Sopenharmony_ci		.ivsize			=	AES_BLOCK_SIZE,
4568c2ecf20Sopenharmony_ci		.setkey			=	ppc_aes_setkey_skcipher,
4578c2ecf20Sopenharmony_ci		.encrypt		=	ppc_cbc_encrypt,
4588c2ecf20Sopenharmony_ci		.decrypt		=	ppc_cbc_decrypt,
4598c2ecf20Sopenharmony_ci	}, {
4608c2ecf20Sopenharmony_ci		.base.cra_name		=	"ctr(aes)",
4618c2ecf20Sopenharmony_ci		.base.cra_driver_name	=	"ctr-ppc-spe",
4628c2ecf20Sopenharmony_ci		.base.cra_priority	=	300,
4638c2ecf20Sopenharmony_ci		.base.cra_blocksize	=	1,
4648c2ecf20Sopenharmony_ci		.base.cra_ctxsize	=	sizeof(struct ppc_aes_ctx),
4658c2ecf20Sopenharmony_ci		.base.cra_module	=	THIS_MODULE,
4668c2ecf20Sopenharmony_ci		.min_keysize		=	AES_MIN_KEY_SIZE,
4678c2ecf20Sopenharmony_ci		.max_keysize		=	AES_MAX_KEY_SIZE,
4688c2ecf20Sopenharmony_ci		.ivsize			=	AES_BLOCK_SIZE,
4698c2ecf20Sopenharmony_ci		.setkey			=	ppc_aes_setkey_skcipher,
4708c2ecf20Sopenharmony_ci		.encrypt		=	ppc_ctr_crypt,
4718c2ecf20Sopenharmony_ci		.decrypt		=	ppc_ctr_crypt,
4728c2ecf20Sopenharmony_ci		.chunksize		=	AES_BLOCK_SIZE,
4738c2ecf20Sopenharmony_ci	}, {
4748c2ecf20Sopenharmony_ci		.base.cra_name		=	"xts(aes)",
4758c2ecf20Sopenharmony_ci		.base.cra_driver_name	=	"xts-ppc-spe",
4768c2ecf20Sopenharmony_ci		.base.cra_priority	=	300,
4778c2ecf20Sopenharmony_ci		.base.cra_blocksize	=	AES_BLOCK_SIZE,
4788c2ecf20Sopenharmony_ci		.base.cra_ctxsize	=	sizeof(struct ppc_xts_ctx),
4798c2ecf20Sopenharmony_ci		.base.cra_module	=	THIS_MODULE,
4808c2ecf20Sopenharmony_ci		.min_keysize		=	AES_MIN_KEY_SIZE * 2,
4818c2ecf20Sopenharmony_ci		.max_keysize		=	AES_MAX_KEY_SIZE * 2,
4828c2ecf20Sopenharmony_ci		.ivsize			=	AES_BLOCK_SIZE,
4838c2ecf20Sopenharmony_ci		.setkey			=	ppc_xts_setkey,
4848c2ecf20Sopenharmony_ci		.encrypt		=	ppc_xts_encrypt,
4858c2ecf20Sopenharmony_ci		.decrypt		=	ppc_xts_decrypt,
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci};
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic int __init ppc_aes_mod_init(void)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	int err;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	err = crypto_register_alg(&aes_cipher_alg);
4948c2ecf20Sopenharmony_ci	if (err)
4958c2ecf20Sopenharmony_ci		return err;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	err = crypto_register_skciphers(aes_skcipher_algs,
4988c2ecf20Sopenharmony_ci					ARRAY_SIZE(aes_skcipher_algs));
4998c2ecf20Sopenharmony_ci	if (err)
5008c2ecf20Sopenharmony_ci		crypto_unregister_alg(&aes_cipher_alg);
5018c2ecf20Sopenharmony_ci	return err;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic void __exit ppc_aes_mod_fini(void)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	crypto_unregister_alg(&aes_cipher_alg);
5078c2ecf20Sopenharmony_ci	crypto_unregister_skciphers(aes_skcipher_algs,
5088c2ecf20Sopenharmony_ci				    ARRAY_SIZE(aes_skcipher_algs));
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cimodule_init(ppc_aes_mod_init);
5128c2ecf20Sopenharmony_cimodule_exit(ppc_aes_mod_fini);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS, SPE optimized");
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes");
5188c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ecb(aes)");
5198c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("cbc(aes)");
5208c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ctr(aes)");
5218c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xts(aes)");
5228c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes-ppc-spe");
523