18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* Glue code for DES encryption optimized for sparc64 crypto opcodes.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 David S. Miller <davem@davemloft.net>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/crypto.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/mm.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
158c2ecf20Sopenharmony_ci#include <crypto/internal/des.h>
168c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/fpumacro.h>
198c2ecf20Sopenharmony_ci#include <asm/pstate.h>
208c2ecf20Sopenharmony_ci#include <asm/elf.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "opcodes.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct des_sparc64_ctx {
258c2ecf20Sopenharmony_ci	u64 encrypt_expkey[DES_EXPKEY_WORDS / 2];
268c2ecf20Sopenharmony_ci	u64 decrypt_expkey[DES_EXPKEY_WORDS / 2];
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct des3_ede_sparc64_ctx {
308c2ecf20Sopenharmony_ci	u64 encrypt_expkey[DES3_EDE_EXPKEY_WORDS / 2];
318c2ecf20Sopenharmony_ci	u64 decrypt_expkey[DES3_EDE_EXPKEY_WORDS / 2];
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void encrypt_to_decrypt(u64 *d, const u64 *e)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	const u64 *s = e + (DES_EXPKEY_WORDS / 2) - 1;
378c2ecf20Sopenharmony_ci	int i;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	for (i = 0; i < DES_EXPKEY_WORDS / 2; i++)
408c2ecf20Sopenharmony_ci		*d++ = *s--;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciextern void des_sparc64_key_expand(const u32 *input_key, u64 *key);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic int des_set_key(struct crypto_tfm *tfm, const u8 *key,
468c2ecf20Sopenharmony_ci		       unsigned int keylen)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct des_sparc64_ctx *dctx = crypto_tfm_ctx(tfm);
498c2ecf20Sopenharmony_ci	int err;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* Even though we have special instructions for key expansion,
528c2ecf20Sopenharmony_ci	 * we call des_verify_key() so that we don't have to write our own
538c2ecf20Sopenharmony_ci	 * weak key detection code.
548c2ecf20Sopenharmony_ci	 */
558c2ecf20Sopenharmony_ci	err = crypto_des_verify_key(tfm, key);
568c2ecf20Sopenharmony_ci	if (err)
578c2ecf20Sopenharmony_ci		return err;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	des_sparc64_key_expand((const u32 *) key, &dctx->encrypt_expkey[0]);
608c2ecf20Sopenharmony_ci	encrypt_to_decrypt(&dctx->decrypt_expkey[0], &dctx->encrypt_expkey[0]);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	return 0;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int des_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *key,
668c2ecf20Sopenharmony_ci				unsigned int keylen)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	return des_set_key(crypto_skcipher_tfm(tfm), key, keylen);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciextern void des_sparc64_crypt(const u64 *key, const u64 *input,
728c2ecf20Sopenharmony_ci			      u64 *output);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic void sparc_des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct des_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
778c2ecf20Sopenharmony_ci	const u64 *K = ctx->encrypt_expkey;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	des_sparc64_crypt(K, (const u64 *) src, (u64 *) dst);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic void sparc_des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct des_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
858c2ecf20Sopenharmony_ci	const u64 *K = ctx->decrypt_expkey;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	des_sparc64_crypt(K, (const u64 *) src, (u64 *) dst);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciextern void des_sparc64_load_keys(const u64 *key);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciextern void des_sparc64_ecb_crypt(const u64 *input, u64 *output,
938c2ecf20Sopenharmony_ci				  unsigned int len);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic int __ecb_crypt(struct skcipher_request *req, bool encrypt)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
988c2ecf20Sopenharmony_ci	const struct des_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
998c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
1008c2ecf20Sopenharmony_ci	unsigned int nbytes;
1018c2ecf20Sopenharmony_ci	int err;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
1048c2ecf20Sopenharmony_ci	if (err)
1058c2ecf20Sopenharmony_ci		return err;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (encrypt)
1088c2ecf20Sopenharmony_ci		des_sparc64_load_keys(&ctx->encrypt_expkey[0]);
1098c2ecf20Sopenharmony_ci	else
1108c2ecf20Sopenharmony_ci		des_sparc64_load_keys(&ctx->decrypt_expkey[0]);
1118c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
1128c2ecf20Sopenharmony_ci		des_sparc64_ecb_crypt(walk.src.virt.addr, walk.dst.virt.addr,
1138c2ecf20Sopenharmony_ci				      round_down(nbytes, DES_BLOCK_SIZE));
1148c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % DES_BLOCK_SIZE);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci	fprs_write(0);
1178c2ecf20Sopenharmony_ci	return err;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	return __ecb_crypt(req, true);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	return __ecb_crypt(req, false);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciextern void des_sparc64_cbc_encrypt(const u64 *input, u64 *output,
1318c2ecf20Sopenharmony_ci				    unsigned int len, u64 *iv);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciextern void des_sparc64_cbc_decrypt(const u64 *input, u64 *output,
1348c2ecf20Sopenharmony_ci				    unsigned int len, u64 *iv);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int __cbc_crypt(struct skcipher_request *req, bool encrypt)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1398c2ecf20Sopenharmony_ci	const struct des_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
1408c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
1418c2ecf20Sopenharmony_ci	unsigned int nbytes;
1428c2ecf20Sopenharmony_ci	int err;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
1458c2ecf20Sopenharmony_ci	if (err)
1468c2ecf20Sopenharmony_ci		return err;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (encrypt)
1498c2ecf20Sopenharmony_ci		des_sparc64_load_keys(&ctx->encrypt_expkey[0]);
1508c2ecf20Sopenharmony_ci	else
1518c2ecf20Sopenharmony_ci		des_sparc64_load_keys(&ctx->decrypt_expkey[0]);
1528c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
1538c2ecf20Sopenharmony_ci		if (encrypt)
1548c2ecf20Sopenharmony_ci			des_sparc64_cbc_encrypt(walk.src.virt.addr,
1558c2ecf20Sopenharmony_ci						walk.dst.virt.addr,
1568c2ecf20Sopenharmony_ci						round_down(nbytes,
1578c2ecf20Sopenharmony_ci							   DES_BLOCK_SIZE),
1588c2ecf20Sopenharmony_ci						walk.iv);
1598c2ecf20Sopenharmony_ci		else
1608c2ecf20Sopenharmony_ci			des_sparc64_cbc_decrypt(walk.src.virt.addr,
1618c2ecf20Sopenharmony_ci						walk.dst.virt.addr,
1628c2ecf20Sopenharmony_ci						round_down(nbytes,
1638c2ecf20Sopenharmony_ci							   DES_BLOCK_SIZE),
1648c2ecf20Sopenharmony_ci						walk.iv);
1658c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % DES_BLOCK_SIZE);
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci	fprs_write(0);
1688c2ecf20Sopenharmony_ci	return err;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	return __cbc_crypt(req, true);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	return __cbc_crypt(req, false);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int des3_ede_set_key(struct crypto_tfm *tfm, const u8 *key,
1828c2ecf20Sopenharmony_ci			    unsigned int keylen)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct des3_ede_sparc64_ctx *dctx = crypto_tfm_ctx(tfm);
1858c2ecf20Sopenharmony_ci	u64 k1[DES_EXPKEY_WORDS / 2];
1868c2ecf20Sopenharmony_ci	u64 k2[DES_EXPKEY_WORDS / 2];
1878c2ecf20Sopenharmony_ci	u64 k3[DES_EXPKEY_WORDS / 2];
1888c2ecf20Sopenharmony_ci	int err;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	err = crypto_des3_ede_verify_key(tfm, key);
1918c2ecf20Sopenharmony_ci	if (err)
1928c2ecf20Sopenharmony_ci		return err;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	des_sparc64_key_expand((const u32 *)key, k1);
1958c2ecf20Sopenharmony_ci	key += DES_KEY_SIZE;
1968c2ecf20Sopenharmony_ci	des_sparc64_key_expand((const u32 *)key, k2);
1978c2ecf20Sopenharmony_ci	key += DES_KEY_SIZE;
1988c2ecf20Sopenharmony_ci	des_sparc64_key_expand((const u32 *)key, k3);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	memcpy(&dctx->encrypt_expkey[0], &k1[0], sizeof(k1));
2018c2ecf20Sopenharmony_ci	encrypt_to_decrypt(&dctx->encrypt_expkey[DES_EXPKEY_WORDS / 2], &k2[0]);
2028c2ecf20Sopenharmony_ci	memcpy(&dctx->encrypt_expkey[(DES_EXPKEY_WORDS / 2) * 2],
2038c2ecf20Sopenharmony_ci	       &k3[0], sizeof(k3));
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	encrypt_to_decrypt(&dctx->decrypt_expkey[0], &k3[0]);
2068c2ecf20Sopenharmony_ci	memcpy(&dctx->decrypt_expkey[DES_EXPKEY_WORDS / 2],
2078c2ecf20Sopenharmony_ci	       &k2[0], sizeof(k2));
2088c2ecf20Sopenharmony_ci	encrypt_to_decrypt(&dctx->decrypt_expkey[(DES_EXPKEY_WORDS / 2) * 2],
2098c2ecf20Sopenharmony_ci			   &k1[0]);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int des3_ede_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *key,
2158c2ecf20Sopenharmony_ci				     unsigned int keylen)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	return des3_ede_set_key(crypto_skcipher_tfm(tfm), key, keylen);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciextern void des3_ede_sparc64_crypt(const u64 *key, const u64 *input,
2218c2ecf20Sopenharmony_ci				   u64 *output);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void sparc_des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct des3_ede_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
2268c2ecf20Sopenharmony_ci	const u64 *K = ctx->encrypt_expkey;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	des3_ede_sparc64_crypt(K, (const u64 *) src, (u64 *) dst);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic void sparc_des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct des3_ede_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
2348c2ecf20Sopenharmony_ci	const u64 *K = ctx->decrypt_expkey;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	des3_ede_sparc64_crypt(K, (const u64 *) src, (u64 *) dst);
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ciextern void des3_ede_sparc64_load_keys(const u64 *key);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ciextern void des3_ede_sparc64_ecb_crypt(const u64 *expkey, const u64 *input,
2428c2ecf20Sopenharmony_ci				       u64 *output, unsigned int len);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int __ecb3_crypt(struct skcipher_request *req, bool encrypt)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2478c2ecf20Sopenharmony_ci	const struct des3_ede_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
2488c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2498c2ecf20Sopenharmony_ci	const u64 *K;
2508c2ecf20Sopenharmony_ci	unsigned int nbytes;
2518c2ecf20Sopenharmony_ci	int err;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
2548c2ecf20Sopenharmony_ci	if (err)
2558c2ecf20Sopenharmony_ci		return err;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (encrypt)
2588c2ecf20Sopenharmony_ci		K = &ctx->encrypt_expkey[0];
2598c2ecf20Sopenharmony_ci	else
2608c2ecf20Sopenharmony_ci		K = &ctx->decrypt_expkey[0];
2618c2ecf20Sopenharmony_ci	des3_ede_sparc64_load_keys(K);
2628c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
2638c2ecf20Sopenharmony_ci		des3_ede_sparc64_ecb_crypt(K, walk.src.virt.addr,
2648c2ecf20Sopenharmony_ci					   walk.dst.virt.addr,
2658c2ecf20Sopenharmony_ci					   round_down(nbytes, DES_BLOCK_SIZE));
2668c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % DES_BLOCK_SIZE);
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	fprs_write(0);
2698c2ecf20Sopenharmony_ci	return err;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int ecb3_encrypt(struct skcipher_request *req)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	return __ecb3_crypt(req, true);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int ecb3_decrypt(struct skcipher_request *req)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	return __ecb3_crypt(req, false);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ciextern void des3_ede_sparc64_cbc_encrypt(const u64 *expkey, const u64 *input,
2838c2ecf20Sopenharmony_ci					 u64 *output, unsigned int len,
2848c2ecf20Sopenharmony_ci					 u64 *iv);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ciextern void des3_ede_sparc64_cbc_decrypt(const u64 *expkey, const u64 *input,
2878c2ecf20Sopenharmony_ci					 u64 *output, unsigned int len,
2888c2ecf20Sopenharmony_ci					 u64 *iv);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int __cbc3_crypt(struct skcipher_request *req, bool encrypt)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2938c2ecf20Sopenharmony_ci	const struct des3_ede_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
2948c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2958c2ecf20Sopenharmony_ci	const u64 *K;
2968c2ecf20Sopenharmony_ci	unsigned int nbytes;
2978c2ecf20Sopenharmony_ci	int err;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
3008c2ecf20Sopenharmony_ci	if (err)
3018c2ecf20Sopenharmony_ci		return err;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (encrypt)
3048c2ecf20Sopenharmony_ci		K = &ctx->encrypt_expkey[0];
3058c2ecf20Sopenharmony_ci	else
3068c2ecf20Sopenharmony_ci		K = &ctx->decrypt_expkey[0];
3078c2ecf20Sopenharmony_ci	des3_ede_sparc64_load_keys(K);
3088c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
3098c2ecf20Sopenharmony_ci		if (encrypt)
3108c2ecf20Sopenharmony_ci			des3_ede_sparc64_cbc_encrypt(K, walk.src.virt.addr,
3118c2ecf20Sopenharmony_ci						     walk.dst.virt.addr,
3128c2ecf20Sopenharmony_ci						     round_down(nbytes,
3138c2ecf20Sopenharmony_ci								DES_BLOCK_SIZE),
3148c2ecf20Sopenharmony_ci						     walk.iv);
3158c2ecf20Sopenharmony_ci		else
3168c2ecf20Sopenharmony_ci			des3_ede_sparc64_cbc_decrypt(K, walk.src.virt.addr,
3178c2ecf20Sopenharmony_ci						     walk.dst.virt.addr,
3188c2ecf20Sopenharmony_ci						     round_down(nbytes,
3198c2ecf20Sopenharmony_ci								DES_BLOCK_SIZE),
3208c2ecf20Sopenharmony_ci						     walk.iv);
3218c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % DES_BLOCK_SIZE);
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci	fprs_write(0);
3248c2ecf20Sopenharmony_ci	return err;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic int cbc3_encrypt(struct skcipher_request *req)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	return __cbc3_crypt(req, true);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int cbc3_decrypt(struct skcipher_request *req)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	return __cbc3_crypt(req, false);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic struct crypto_alg cipher_algs[] = {
3388c2ecf20Sopenharmony_ci	{
3398c2ecf20Sopenharmony_ci		.cra_name		= "des",
3408c2ecf20Sopenharmony_ci		.cra_driver_name	= "des-sparc64",
3418c2ecf20Sopenharmony_ci		.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
3428c2ecf20Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3438c2ecf20Sopenharmony_ci		.cra_blocksize		= DES_BLOCK_SIZE,
3448c2ecf20Sopenharmony_ci		.cra_ctxsize		= sizeof(struct des_sparc64_ctx),
3458c2ecf20Sopenharmony_ci		.cra_alignmask		= 7,
3468c2ecf20Sopenharmony_ci		.cra_module		= THIS_MODULE,
3478c2ecf20Sopenharmony_ci		.cra_u	= {
3488c2ecf20Sopenharmony_ci			.cipher	= {
3498c2ecf20Sopenharmony_ci				.cia_min_keysize	= DES_KEY_SIZE,
3508c2ecf20Sopenharmony_ci				.cia_max_keysize	= DES_KEY_SIZE,
3518c2ecf20Sopenharmony_ci				.cia_setkey		= des_set_key,
3528c2ecf20Sopenharmony_ci				.cia_encrypt		= sparc_des_encrypt,
3538c2ecf20Sopenharmony_ci				.cia_decrypt		= sparc_des_decrypt
3548c2ecf20Sopenharmony_ci			}
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci	}, {
3578c2ecf20Sopenharmony_ci		.cra_name		= "des3_ede",
3588c2ecf20Sopenharmony_ci		.cra_driver_name	= "des3_ede-sparc64",
3598c2ecf20Sopenharmony_ci		.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
3608c2ecf20Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3618c2ecf20Sopenharmony_ci		.cra_blocksize		= DES3_EDE_BLOCK_SIZE,
3628c2ecf20Sopenharmony_ci		.cra_ctxsize		= sizeof(struct des3_ede_sparc64_ctx),
3638c2ecf20Sopenharmony_ci		.cra_alignmask		= 7,
3648c2ecf20Sopenharmony_ci		.cra_module		= THIS_MODULE,
3658c2ecf20Sopenharmony_ci		.cra_u	= {
3668c2ecf20Sopenharmony_ci			.cipher	= {
3678c2ecf20Sopenharmony_ci				.cia_min_keysize	= DES3_EDE_KEY_SIZE,
3688c2ecf20Sopenharmony_ci				.cia_max_keysize	= DES3_EDE_KEY_SIZE,
3698c2ecf20Sopenharmony_ci				.cia_setkey		= des3_ede_set_key,
3708c2ecf20Sopenharmony_ci				.cia_encrypt		= sparc_des3_ede_encrypt,
3718c2ecf20Sopenharmony_ci				.cia_decrypt		= sparc_des3_ede_decrypt
3728c2ecf20Sopenharmony_ci			}
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic struct skcipher_alg skcipher_algs[] = {
3788c2ecf20Sopenharmony_ci	{
3798c2ecf20Sopenharmony_ci		.base.cra_name		= "ecb(des)",
3808c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "ecb-des-sparc64",
3818c2ecf20Sopenharmony_ci		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
3828c2ecf20Sopenharmony_ci		.base.cra_blocksize	= DES_BLOCK_SIZE,
3838c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des_sparc64_ctx),
3848c2ecf20Sopenharmony_ci		.base.cra_alignmask	= 7,
3858c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
3868c2ecf20Sopenharmony_ci		.min_keysize		= DES_KEY_SIZE,
3878c2ecf20Sopenharmony_ci		.max_keysize		= DES_KEY_SIZE,
3888c2ecf20Sopenharmony_ci		.setkey			= des_set_key_skcipher,
3898c2ecf20Sopenharmony_ci		.encrypt		= ecb_encrypt,
3908c2ecf20Sopenharmony_ci		.decrypt		= ecb_decrypt,
3918c2ecf20Sopenharmony_ci	}, {
3928c2ecf20Sopenharmony_ci		.base.cra_name		= "cbc(des)",
3938c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "cbc-des-sparc64",
3948c2ecf20Sopenharmony_ci		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
3958c2ecf20Sopenharmony_ci		.base.cra_blocksize	= DES_BLOCK_SIZE,
3968c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des_sparc64_ctx),
3978c2ecf20Sopenharmony_ci		.base.cra_alignmask	= 7,
3988c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
3998c2ecf20Sopenharmony_ci		.min_keysize		= DES_KEY_SIZE,
4008c2ecf20Sopenharmony_ci		.max_keysize		= DES_KEY_SIZE,
4018c2ecf20Sopenharmony_ci		.ivsize			= DES_BLOCK_SIZE,
4028c2ecf20Sopenharmony_ci		.setkey			= des_set_key_skcipher,
4038c2ecf20Sopenharmony_ci		.encrypt		= cbc_encrypt,
4048c2ecf20Sopenharmony_ci		.decrypt		= cbc_decrypt,
4058c2ecf20Sopenharmony_ci	}, {
4068c2ecf20Sopenharmony_ci		.base.cra_name		= "ecb(des3_ede)",
4078c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "ecb-des3_ede-sparc64",
4088c2ecf20Sopenharmony_ci		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
4098c2ecf20Sopenharmony_ci		.base.cra_blocksize	= DES3_EDE_BLOCK_SIZE,
4108c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des3_ede_sparc64_ctx),
4118c2ecf20Sopenharmony_ci		.base.cra_alignmask	= 7,
4128c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
4138c2ecf20Sopenharmony_ci		.min_keysize		= DES3_EDE_KEY_SIZE,
4148c2ecf20Sopenharmony_ci		.max_keysize		= DES3_EDE_KEY_SIZE,
4158c2ecf20Sopenharmony_ci		.setkey			= des3_ede_set_key_skcipher,
4168c2ecf20Sopenharmony_ci		.encrypt		= ecb3_encrypt,
4178c2ecf20Sopenharmony_ci		.decrypt		= ecb3_decrypt,
4188c2ecf20Sopenharmony_ci	}, {
4198c2ecf20Sopenharmony_ci		.base.cra_name		= "cbc(des3_ede)",
4208c2ecf20Sopenharmony_ci		.base.cra_driver_name	= "cbc-des3_ede-sparc64",
4218c2ecf20Sopenharmony_ci		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
4228c2ecf20Sopenharmony_ci		.base.cra_blocksize	= DES3_EDE_BLOCK_SIZE,
4238c2ecf20Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct des3_ede_sparc64_ctx),
4248c2ecf20Sopenharmony_ci		.base.cra_alignmask	= 7,
4258c2ecf20Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
4268c2ecf20Sopenharmony_ci		.min_keysize		= DES3_EDE_KEY_SIZE,
4278c2ecf20Sopenharmony_ci		.max_keysize		= DES3_EDE_KEY_SIZE,
4288c2ecf20Sopenharmony_ci		.ivsize			= DES3_EDE_BLOCK_SIZE,
4298c2ecf20Sopenharmony_ci		.setkey			= des3_ede_set_key_skcipher,
4308c2ecf20Sopenharmony_ci		.encrypt		= cbc3_encrypt,
4318c2ecf20Sopenharmony_ci		.decrypt		= cbc3_decrypt,
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic bool __init sparc64_has_des_opcode(void)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	unsigned long cfr;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
4408c2ecf20Sopenharmony_ci		return false;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
4438c2ecf20Sopenharmony_ci	if (!(cfr & CFR_DES))
4448c2ecf20Sopenharmony_ci		return false;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	return true;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic int __init des_sparc64_mod_init(void)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	int err;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (!sparc64_has_des_opcode()) {
4548c2ecf20Sopenharmony_ci		pr_info("sparc64 des opcodes not available.\n");
4558c2ecf20Sopenharmony_ci		return -ENODEV;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci	pr_info("Using sparc64 des opcodes optimized DES implementation\n");
4588c2ecf20Sopenharmony_ci	err = crypto_register_algs(cipher_algs, ARRAY_SIZE(cipher_algs));
4598c2ecf20Sopenharmony_ci	if (err)
4608c2ecf20Sopenharmony_ci		return err;
4618c2ecf20Sopenharmony_ci	err = crypto_register_skciphers(skcipher_algs,
4628c2ecf20Sopenharmony_ci					ARRAY_SIZE(skcipher_algs));
4638c2ecf20Sopenharmony_ci	if (err)
4648c2ecf20Sopenharmony_ci		crypto_unregister_algs(cipher_algs, ARRAY_SIZE(cipher_algs));
4658c2ecf20Sopenharmony_ci	return err;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic void __exit des_sparc64_mod_fini(void)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	crypto_unregister_algs(cipher_algs, ARRAY_SIZE(cipher_algs));
4718c2ecf20Sopenharmony_ci	crypto_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cimodule_init(des_sparc64_mod_init);
4758c2ecf20Sopenharmony_cimodule_exit(des_sparc64_mod_fini);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms, sparc64 des opcode accelerated");
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("des");
4818c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("des3_ede");
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci#include "crop_devid.c"
484