Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / arch / powerpc / crypto / chacha-p10-glue.c
blob7c728755852e1a2cfe06f46cca29eb339be8f4b8
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * PowerPC P10 (ppc64le) accelerated ChaCha and XChaCha stream ciphers,
4 * including ChaCha20 (RFC7539)
6 * Copyright 2023- IBM Corp. All rights reserved.
7 */
9 #include <crypto/algapi.h>
10 #include <crypto/internal/chacha.h>
11 #include <crypto/internal/simd.h>
12 #include <crypto/internal/skcipher.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/cpufeature.h>
16 #include <linux/sizes.h>
17 #include <asm/simd.h>
18 #include <asm/switch_to.h>
20 asmlinkage void chacha_p10le_8x(u32 *state, u8 *dst, const u8 *src,
21 unsigned int len, int nrounds);
23 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_p10);
25 static void vsx_begin(void)
27 preempt_disable();
28 enable_kernel_vsx();
31 static void vsx_end(void)
33 disable_kernel_vsx();
34 preempt_enable();
37 static void chacha_p10_do_8x(u32 *state, u8 *dst, const u8 *src,
38 unsigned int bytes, int nrounds)
40 unsigned int l = bytes & ~0x0FF;
42 if (l > 0) {
43 chacha_p10le_8x(state, dst, src, l, nrounds);
44 bytes -= l;
45 src += l;
46 dst += l;
47 state[12] += l / CHACHA_BLOCK_SIZE;
50 if (bytes > 0)
51 chacha_crypt_generic(state, dst, src, bytes, nrounds);
54 void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
56 hchacha_block_generic(state, stream, nrounds);
58 EXPORT_SYMBOL(hchacha_block_arch);
60 void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
62 chacha_init_generic(state, key, iv);
64 EXPORT_SYMBOL(chacha_init_arch);
66 void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
67 int nrounds)
69 if (!static_branch_likely(&have_p10) || bytes <= CHACHA_BLOCK_SIZE ||
70 !crypto_simd_usable())
71 return chacha_crypt_generic(state, dst, src, bytes, nrounds);
73 do {
74 unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
76 vsx_begin();
77 chacha_p10_do_8x(state, dst, src, todo, nrounds);
78 vsx_end();
80 bytes -= todo;
81 src += todo;
82 dst += todo;
83 } while (bytes);
85 EXPORT_SYMBOL(chacha_crypt_arch);
87 static int chacha_p10_stream_xor(struct skcipher_request *req,
88 const struct chacha_ctx *ctx, const u8 *iv)
90 struct skcipher_walk walk;
91 u32 state[16];
92 int err;
94 err = skcipher_walk_virt(&walk, req, false);
95 if (err)
96 return err;
98 chacha_init_generic(state, ctx->key, iv);
100 while (walk.nbytes > 0) {
101 unsigned int nbytes = walk.nbytes;
103 if (nbytes < walk.total)
104 nbytes = rounddown(nbytes, walk.stride);
106 if (!crypto_simd_usable()) {
107 chacha_crypt_generic(state, walk.dst.virt.addr,
108 walk.src.virt.addr, nbytes,
109 ctx->nrounds);
110 } else {
111 vsx_begin();
112 chacha_p10_do_8x(state, walk.dst.virt.addr,
113 walk.src.virt.addr, nbytes, ctx->nrounds);
114 vsx_end();
116 err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
117 if (err)
118 break;
121 return err;
124 static int chacha_p10(struct skcipher_request *req)
126 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
127 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
129 return chacha_p10_stream_xor(req, ctx, req->iv);
132 static int xchacha_p10(struct skcipher_request *req)
134 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
135 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
136 struct chacha_ctx subctx;
137 u32 state[16];
138 u8 real_iv[16];
140 chacha_init_generic(state, ctx->key, req->iv);
141 hchacha_block_arch(state, subctx.key, ctx->nrounds);
142 subctx.nrounds = ctx->nrounds;
144 memcpy(&real_iv[0], req->iv + 24, 8);
145 memcpy(&real_iv[8], req->iv + 16, 8);
146 return chacha_p10_stream_xor(req, &subctx, real_iv);
149 static struct skcipher_alg algs[] = {
151 .base.cra_name = "chacha20",
152 .base.cra_driver_name = "chacha20-p10",
153 .base.cra_priority = 300,
154 .base.cra_blocksize = 1,
155 .base.cra_ctxsize = sizeof(struct chacha_ctx),
156 .base.cra_module = THIS_MODULE,
158 .min_keysize = CHACHA_KEY_SIZE,
159 .max_keysize = CHACHA_KEY_SIZE,
160 .ivsize = CHACHA_IV_SIZE,
161 .chunksize = CHACHA_BLOCK_SIZE,
162 .setkey = chacha20_setkey,
163 .encrypt = chacha_p10,
164 .decrypt = chacha_p10,
165 }, {
166 .base.cra_name = "xchacha20",
167 .base.cra_driver_name = "xchacha20-p10",
168 .base.cra_priority = 300,
169 .base.cra_blocksize = 1,
170 .base.cra_ctxsize = sizeof(struct chacha_ctx),
171 .base.cra_module = THIS_MODULE,
173 .min_keysize = CHACHA_KEY_SIZE,
174 .max_keysize = CHACHA_KEY_SIZE,
175 .ivsize = XCHACHA_IV_SIZE,
176 .chunksize = CHACHA_BLOCK_SIZE,
177 .setkey = chacha20_setkey,
178 .encrypt = xchacha_p10,
179 .decrypt = xchacha_p10,
180 }, {
181 .base.cra_name = "xchacha12",
182 .base.cra_driver_name = "xchacha12-p10",
183 .base.cra_priority = 300,
184 .base.cra_blocksize = 1,
185 .base.cra_ctxsize = sizeof(struct chacha_ctx),
186 .base.cra_module = THIS_MODULE,
188 .min_keysize = CHACHA_KEY_SIZE,
189 .max_keysize = CHACHA_KEY_SIZE,
190 .ivsize = XCHACHA_IV_SIZE,
191 .chunksize = CHACHA_BLOCK_SIZE,
192 .setkey = chacha12_setkey,
193 .encrypt = xchacha_p10,
194 .decrypt = xchacha_p10,
198 static int __init chacha_p10_init(void)
200 if (!cpu_has_feature(CPU_FTR_ARCH_31))
201 return 0;
203 static_branch_enable(&have_p10);
205 return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
208 static void __exit chacha_p10_exit(void)
210 if (!static_branch_likely(&have_p10))
211 return;
213 crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
216 module_init(chacha_p10_init);
217 module_exit(chacha_p10_exit);
219 MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (P10 accelerated)");
220 MODULE_AUTHOR("Danny Tsen <dtsen@linux.ibm.com>");
221 MODULE_LICENSE("GPL v2");
222 MODULE_ALIAS_CRYPTO("chacha20");
223 MODULE_ALIAS_CRYPTO("chacha20-p10");
224 MODULE_ALIAS_CRYPTO("xchacha20");
225 MODULE_ALIAS_CRYPTO("xchacha20-p10");
226 MODULE_ALIAS_CRYPTO("xchacha12");
227 MODULE_ALIAS_CRYPTO("xchacha12-p10");