xref: /openbmc/linux/arch/x86/crypto/camellia_aesni_avx_glue.c (revision a1f91ecf812ac333ee2897f3eb2d8f4f6b4ce942)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Glue Code for x86_64/AVX/AES-NI assembler optimized version of Camellia
4  *
5  * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
6  */
7 
8 #include <asm/crypto/camellia.h>
9 #include <asm/crypto/glue_helper.h>
10 #include <crypto/algapi.h>
11 #include <crypto/internal/simd.h>
12 #include <linux/crypto.h>
13 #include <linux/err.h>
14 #include <linux/module.h>
15 #include <linux/types.h>
16 
17 #define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
18 
19 /* 16-way parallel cipher functions (avx/aes-ni) */
20 asmlinkage void camellia_ecb_enc_16way(const void *ctx, u8 *dst, const u8 *src);
21 EXPORT_SYMBOL_GPL(camellia_ecb_enc_16way);
22 
23 asmlinkage void camellia_ecb_dec_16way(const void *ctx, u8 *dst, const u8 *src);
24 EXPORT_SYMBOL_GPL(camellia_ecb_dec_16way);
25 
26 asmlinkage void camellia_cbc_dec_16way(const void *ctx, u8 *dst, const u8 *src);
27 EXPORT_SYMBOL_GPL(camellia_cbc_dec_16way);
28 
29 static const struct common_glue_ctx camellia_enc = {
30 	.num_funcs = 3,
31 	.fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
32 
33 	.funcs = { {
34 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
35 		.fn_u = { .ecb = camellia_ecb_enc_16way }
36 	}, {
37 		.num_blocks = 2,
38 		.fn_u = { .ecb = camellia_enc_blk_2way }
39 	}, {
40 		.num_blocks = 1,
41 		.fn_u = { .ecb = camellia_enc_blk }
42 	} }
43 };
44 
45 static const struct common_glue_ctx camellia_dec = {
46 	.num_funcs = 3,
47 	.fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
48 
49 	.funcs = { {
50 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
51 		.fn_u = { .ecb = camellia_ecb_dec_16way }
52 	}, {
53 		.num_blocks = 2,
54 		.fn_u = { .ecb = camellia_dec_blk_2way }
55 	}, {
56 		.num_blocks = 1,
57 		.fn_u = { .ecb = camellia_dec_blk }
58 	} }
59 };
60 
61 static const struct common_glue_ctx camellia_dec_cbc = {
62 	.num_funcs = 3,
63 	.fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
64 
65 	.funcs = { {
66 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
67 		.fn_u = { .cbc = camellia_cbc_dec_16way }
68 	}, {
69 		.num_blocks = 2,
70 		.fn_u = { .cbc = camellia_decrypt_cbc_2way }
71 	}, {
72 		.num_blocks = 1,
73 		.fn_u = { .cbc = camellia_dec_blk }
74 	} }
75 };
76 
77 static int camellia_setkey(struct crypto_skcipher *tfm, const u8 *key,
78 			   unsigned int keylen)
79 {
80 	return __camellia_setkey(crypto_skcipher_ctx(tfm), key, keylen);
81 }
82 
83 static int ecb_encrypt(struct skcipher_request *req)
84 {
85 	return glue_ecb_req_128bit(&camellia_enc, req);
86 }
87 
88 static int ecb_decrypt(struct skcipher_request *req)
89 {
90 	return glue_ecb_req_128bit(&camellia_dec, req);
91 }
92 
93 static int cbc_encrypt(struct skcipher_request *req)
94 {
95 	return glue_cbc_encrypt_req_128bit(camellia_enc_blk, req);
96 }
97 
98 static int cbc_decrypt(struct skcipher_request *req)
99 {
100 	return glue_cbc_decrypt_req_128bit(&camellia_dec_cbc, req);
101 }
102 
103 static struct skcipher_alg camellia_algs[] = {
104 	{
105 		.base.cra_name		= "__ecb(camellia)",
106 		.base.cra_driver_name	= "__ecb-camellia-aesni",
107 		.base.cra_priority	= 400,
108 		.base.cra_flags		= CRYPTO_ALG_INTERNAL,
109 		.base.cra_blocksize	= CAMELLIA_BLOCK_SIZE,
110 		.base.cra_ctxsize	= sizeof(struct camellia_ctx),
111 		.base.cra_module	= THIS_MODULE,
112 		.min_keysize		= CAMELLIA_MIN_KEY_SIZE,
113 		.max_keysize		= CAMELLIA_MAX_KEY_SIZE,
114 		.setkey			= camellia_setkey,
115 		.encrypt		= ecb_encrypt,
116 		.decrypt		= ecb_decrypt,
117 	}, {
118 		.base.cra_name		= "__cbc(camellia)",
119 		.base.cra_driver_name	= "__cbc-camellia-aesni",
120 		.base.cra_priority	= 400,
121 		.base.cra_flags		= CRYPTO_ALG_INTERNAL,
122 		.base.cra_blocksize	= CAMELLIA_BLOCK_SIZE,
123 		.base.cra_ctxsize	= sizeof(struct camellia_ctx),
124 		.base.cra_module	= THIS_MODULE,
125 		.min_keysize		= CAMELLIA_MIN_KEY_SIZE,
126 		.max_keysize		= CAMELLIA_MAX_KEY_SIZE,
127 		.ivsize			= CAMELLIA_BLOCK_SIZE,
128 		.setkey			= camellia_setkey,
129 		.encrypt		= cbc_encrypt,
130 		.decrypt		= cbc_decrypt,
131 	}
132 };
133 
134 static struct simd_skcipher_alg *camellia_simd_algs[ARRAY_SIZE(camellia_algs)];
135 
136 static int __init camellia_aesni_init(void)
137 {
138 	const char *feature_name;
139 
140 	if (!boot_cpu_has(X86_FEATURE_AVX) ||
141 	    !boot_cpu_has(X86_FEATURE_AES) ||
142 	    !boot_cpu_has(X86_FEATURE_OSXSAVE)) {
143 		pr_info("AVX or AES-NI instructions are not detected.\n");
144 		return -ENODEV;
145 	}
146 
147 	if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,
148 				&feature_name)) {
149 		pr_info("CPU feature '%s' is not supported.\n", feature_name);
150 		return -ENODEV;
151 	}
152 
153 	return simd_register_skciphers_compat(camellia_algs,
154 					      ARRAY_SIZE(camellia_algs),
155 					      camellia_simd_algs);
156 }
157 
158 static void __exit camellia_aesni_fini(void)
159 {
160 	simd_unregister_skciphers(camellia_algs, ARRAY_SIZE(camellia_algs),
161 				  camellia_simd_algs);
162 }
163 
164 module_init(camellia_aesni_init);
165 module_exit(camellia_aesni_fini);
166 
167 MODULE_LICENSE("GPL");
168 MODULE_DESCRIPTION("Camellia Cipher Algorithm, AES-NI/AVX optimized");
169 MODULE_ALIAS_CRYPTO("camellia");
170 MODULE_ALIAS_CRYPTO("camellia-asm");
171