1937c30d7SJussi Kivilinna /*
2937c30d7SJussi Kivilinna  * Glue Code for SSE2 assembler versions of Serpent Cipher
3937c30d7SJussi Kivilinna  *
4937c30d7SJussi Kivilinna  * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
5937c30d7SJussi Kivilinna  *
6937c30d7SJussi Kivilinna  * Glue code based on aesni-intel_glue.c by:
7937c30d7SJussi Kivilinna  *  Copyright (C) 2008, Intel Corp.
8937c30d7SJussi Kivilinna  *    Author: Huang Ying <ying.huang@intel.com>
9937c30d7SJussi Kivilinna  *
10937c30d7SJussi Kivilinna  * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
11937c30d7SJussi Kivilinna  *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
12937c30d7SJussi Kivilinna  * CTR part based on code (crypto/ctr.c) by:
13937c30d7SJussi Kivilinna  *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
14937c30d7SJussi Kivilinna  *
15937c30d7SJussi Kivilinna  * This program is free software; you can redistribute it and/or modify
16937c30d7SJussi Kivilinna  * it under the terms of the GNU General Public License as published by
17937c30d7SJussi Kivilinna  * the Free Software Foundation; either version 2 of the License, or
18937c30d7SJussi Kivilinna  * (at your option) any later version.
19937c30d7SJussi Kivilinna  *
20937c30d7SJussi Kivilinna  * This program is distributed in the hope that it will be useful,
21937c30d7SJussi Kivilinna  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22937c30d7SJussi Kivilinna  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23937c30d7SJussi Kivilinna  * GNU General Public License for more details.
24937c30d7SJussi Kivilinna  *
25937c30d7SJussi Kivilinna  * You should have received a copy of the GNU General Public License
26937c30d7SJussi Kivilinna  * along with this program; if not, write to the Free Software
27937c30d7SJussi Kivilinna  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
28937c30d7SJussi Kivilinna  * USA
29937c30d7SJussi Kivilinna  *
30937c30d7SJussi Kivilinna  */
31937c30d7SJussi Kivilinna 
32937c30d7SJussi Kivilinna #include <linux/module.h>
33937c30d7SJussi Kivilinna #include <linux/hardirq.h>
34937c30d7SJussi Kivilinna #include <linux/types.h>
35937c30d7SJussi Kivilinna #include <linux/crypto.h>
36937c30d7SJussi Kivilinna #include <linux/err.h>
37937c30d7SJussi Kivilinna #include <crypto/algapi.h>
38937c30d7SJussi Kivilinna #include <crypto/serpent.h>
39937c30d7SJussi Kivilinna #include <crypto/cryptd.h>
40937c30d7SJussi Kivilinna #include <crypto/b128ops.h>
41937c30d7SJussi Kivilinna #include <crypto/ctr.h>
4218482053SJussi Kivilinna #include <crypto/lrw.h>
435962f8b6SJussi Kivilinna #include <crypto/xts.h>
44937c30d7SJussi Kivilinna #include <asm/i387.h>
453387e7d6SJussi Kivilinna #include <asm/serpent-sse2.h>
46ffaf9156SJussi Kivilinna #include <asm/crypto/ablk_helper.h>
47937c30d7SJussi Kivilinna #include <crypto/scatterwalk.h>
48937c30d7SJussi Kivilinna #include <linux/workqueue.h>
49937c30d7SJussi Kivilinna #include <linux/spinlock.h>
50937c30d7SJussi Kivilinna 
51e81792fbSJussi Kivilinna typedef void (*common_glue_func_t)(void *ctx, u8 *dst, const u8 *src);
52e81792fbSJussi Kivilinna typedef void (*common_glue_cbc_func_t)(void *ctx, u128 *dst, const u128 *src);
53e81792fbSJussi Kivilinna typedef void (*common_glue_ctr_func_t)(void *ctx, u128 *dst, const u128 *src,
54e81792fbSJussi Kivilinna 				       u128 *iv);
55e81792fbSJussi Kivilinna 
56e81792fbSJussi Kivilinna #define GLUE_FUNC_CAST(fn) ((common_glue_func_t)(fn))
57e81792fbSJussi Kivilinna #define GLUE_CBC_FUNC_CAST(fn) ((common_glue_cbc_func_t)(fn))
58e81792fbSJussi Kivilinna #define GLUE_CTR_FUNC_CAST(fn) ((common_glue_ctr_func_t)(fn))
59e81792fbSJussi Kivilinna 
60e81792fbSJussi Kivilinna struct common_glue_func_entry {
61e81792fbSJussi Kivilinna 	unsigned int num_blocks; /* number of blocks that @fn will process */
62e81792fbSJussi Kivilinna 	union {
63e81792fbSJussi Kivilinna 		common_glue_func_t ecb;
64e81792fbSJussi Kivilinna 		common_glue_cbc_func_t cbc;
65e81792fbSJussi Kivilinna 		common_glue_ctr_func_t ctr;
66e81792fbSJussi Kivilinna 	} fn_u;
67e81792fbSJussi Kivilinna };
68e81792fbSJussi Kivilinna 
69e81792fbSJussi Kivilinna struct common_glue_ctx {
70e81792fbSJussi Kivilinna 	unsigned int num_funcs;
71e81792fbSJussi Kivilinna 	int fpu_blocks_limit; /* -1 means fpu not needed at all */
72e81792fbSJussi Kivilinna 
73e81792fbSJussi Kivilinna 	/*
74e81792fbSJussi Kivilinna 	 * First funcs entry must have largest num_blocks and last funcs entry
75e81792fbSJussi Kivilinna 	 * must have num_blocks == 1!
76e81792fbSJussi Kivilinna 	 */
77e81792fbSJussi Kivilinna 	struct common_glue_func_entry funcs[];
78e81792fbSJussi Kivilinna };
79e81792fbSJussi Kivilinna 
80e81792fbSJussi Kivilinna static inline bool glue_fpu_begin(unsigned int bsize, int fpu_blocks_limit,
81e81792fbSJussi Kivilinna 				  struct blkcipher_desc *desc,
82e81792fbSJussi Kivilinna 				  bool fpu_enabled, unsigned int nbytes)
83937c30d7SJussi Kivilinna {
84e81792fbSJussi Kivilinna 	if (likely(fpu_blocks_limit < 0))
85e81792fbSJussi Kivilinna 		return false;
86e81792fbSJussi Kivilinna 
87937c30d7SJussi Kivilinna 	if (fpu_enabled)
88937c30d7SJussi Kivilinna 		return true;
89937c30d7SJussi Kivilinna 
90e81792fbSJussi Kivilinna 	/*
91e81792fbSJussi Kivilinna 	 * Vector-registers are only used when chunk to be processed is large
92e81792fbSJussi Kivilinna 	 * enough, so do not enable FPU until it is necessary.
93937c30d7SJussi Kivilinna 	 */
94e81792fbSJussi Kivilinna 	if (nbytes < bsize * (unsigned int)fpu_blocks_limit)
95937c30d7SJussi Kivilinna 		return false;
96937c30d7SJussi Kivilinna 
97e81792fbSJussi Kivilinna 	if (desc) {
98e81792fbSJussi Kivilinna 		/* prevent sleeping if FPU is in use */
99e81792fbSJussi Kivilinna 		desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
100e81792fbSJussi Kivilinna 	}
101e81792fbSJussi Kivilinna 
102937c30d7SJussi Kivilinna 	kernel_fpu_begin();
103937c30d7SJussi Kivilinna 	return true;
104937c30d7SJussi Kivilinna }
105937c30d7SJussi Kivilinna 
106e81792fbSJussi Kivilinna static inline void glue_fpu_end(bool fpu_enabled)
107937c30d7SJussi Kivilinna {
108937c30d7SJussi Kivilinna 	if (fpu_enabled)
109937c30d7SJussi Kivilinna 		kernel_fpu_end();
110937c30d7SJussi Kivilinna }
111937c30d7SJussi Kivilinna 
112e81792fbSJussi Kivilinna static int __glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx,
113e81792fbSJussi Kivilinna 				   struct blkcipher_desc *desc,
114e81792fbSJussi Kivilinna 				   struct blkcipher_walk *walk)
115937c30d7SJussi Kivilinna {
116e81792fbSJussi Kivilinna 	void *ctx = crypto_blkcipher_ctx(desc->tfm);
117e81792fbSJussi Kivilinna 	const unsigned int bsize = 128 / 8;
118e81792fbSJussi Kivilinna 	unsigned int nbytes, i, func_bytes;
119937c30d7SJussi Kivilinna 	bool fpu_enabled = false;
120937c30d7SJussi Kivilinna 	int err;
121937c30d7SJussi Kivilinna 
122937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt(desc, walk);
123937c30d7SJussi Kivilinna 
124937c30d7SJussi Kivilinna 	while ((nbytes = walk->nbytes)) {
125937c30d7SJussi Kivilinna 		u8 *wsrc = walk->src.virt.addr;
126937c30d7SJussi Kivilinna 		u8 *wdst = walk->dst.virt.addr;
127937c30d7SJussi Kivilinna 
128e81792fbSJussi Kivilinna 		fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
129e81792fbSJussi Kivilinna 					     desc, fpu_enabled, nbytes);
130e81792fbSJussi Kivilinna 
131e81792fbSJussi Kivilinna 		for (i = 0; i < gctx->num_funcs; i++) {
132e81792fbSJussi Kivilinna 			func_bytes = bsize * gctx->funcs[i].num_blocks;
133937c30d7SJussi Kivilinna 
134937c30d7SJussi Kivilinna 			/* Process multi-block batch */
135e81792fbSJussi Kivilinna 			if (nbytes >= func_bytes) {
136937c30d7SJussi Kivilinna 				do {
137e81792fbSJussi Kivilinna 					gctx->funcs[i].fn_u.ecb(ctx, wdst,
138e81792fbSJussi Kivilinna 								wsrc);
139937c30d7SJussi Kivilinna 
140e81792fbSJussi Kivilinna 					wsrc += func_bytes;
141e81792fbSJussi Kivilinna 					wdst += func_bytes;
142e81792fbSJussi Kivilinna 					nbytes -= func_bytes;
143e81792fbSJussi Kivilinna 				} while (nbytes >= func_bytes);
144937c30d7SJussi Kivilinna 
145937c30d7SJussi Kivilinna 				if (nbytes < bsize)
146937c30d7SJussi Kivilinna 					goto done;
147937c30d7SJussi Kivilinna 			}
148e81792fbSJussi Kivilinna 		}
149937c30d7SJussi Kivilinna 
150937c30d7SJussi Kivilinna done:
151937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, walk, nbytes);
152937c30d7SJussi Kivilinna 	}
153937c30d7SJussi Kivilinna 
154e81792fbSJussi Kivilinna 	glue_fpu_end(fpu_enabled);
155937c30d7SJussi Kivilinna 	return err;
156937c30d7SJussi Kivilinna }
157937c30d7SJussi Kivilinna 
158e81792fbSJussi Kivilinna int glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx,
159e81792fbSJussi Kivilinna 			  struct blkcipher_desc *desc, struct scatterlist *dst,
160937c30d7SJussi Kivilinna 			  struct scatterlist *src, unsigned int nbytes)
161937c30d7SJussi Kivilinna {
162937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
163937c30d7SJussi Kivilinna 
164937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
165e81792fbSJussi Kivilinna 	return __glue_ecb_crypt_128bit(gctx, desc, &walk);
166937c30d7SJussi Kivilinna }
167937c30d7SJussi Kivilinna 
168e81792fbSJussi Kivilinna static unsigned int __glue_cbc_encrypt_128bit(const common_glue_func_t fn,
169e81792fbSJussi Kivilinna 					      struct blkcipher_desc *desc,
170937c30d7SJussi Kivilinna 					      struct blkcipher_walk *walk)
171937c30d7SJussi Kivilinna {
172e81792fbSJussi Kivilinna 	void *ctx = crypto_blkcipher_ctx(desc->tfm);
173e81792fbSJussi Kivilinna 	const unsigned int bsize = 128 / 8;
174937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
175937c30d7SJussi Kivilinna 	u128 *src = (u128 *)walk->src.virt.addr;
176937c30d7SJussi Kivilinna 	u128 *dst = (u128 *)walk->dst.virt.addr;
177937c30d7SJussi Kivilinna 	u128 *iv = (u128 *)walk->iv;
178937c30d7SJussi Kivilinna 
179937c30d7SJussi Kivilinna 	do {
180937c30d7SJussi Kivilinna 		u128_xor(dst, src, iv);
181e81792fbSJussi Kivilinna 		fn(ctx, (u8 *)dst, (u8 *)dst);
182937c30d7SJussi Kivilinna 		iv = dst;
183937c30d7SJussi Kivilinna 
184937c30d7SJussi Kivilinna 		src += 1;
185937c30d7SJussi Kivilinna 		dst += 1;
186937c30d7SJussi Kivilinna 		nbytes -= bsize;
187937c30d7SJussi Kivilinna 	} while (nbytes >= bsize);
188937c30d7SJussi Kivilinna 
189937c30d7SJussi Kivilinna 	u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
190937c30d7SJussi Kivilinna 	return nbytes;
191937c30d7SJussi Kivilinna }
192937c30d7SJussi Kivilinna 
193e81792fbSJussi Kivilinna int glue_cbc_encrypt_128bit(const common_glue_func_t fn,
194e81792fbSJussi Kivilinna 			    struct blkcipher_desc *desc,
195e81792fbSJussi Kivilinna 			    struct scatterlist *dst,
196937c30d7SJussi Kivilinna 			    struct scatterlist *src, unsigned int nbytes)
197937c30d7SJussi Kivilinna {
198937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
199937c30d7SJussi Kivilinna 	int err;
200937c30d7SJussi Kivilinna 
201937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
202937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
203937c30d7SJussi Kivilinna 
204937c30d7SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
205e81792fbSJussi Kivilinna 		nbytes = __glue_cbc_encrypt_128bit(fn, desc, &walk);
206937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
207937c30d7SJussi Kivilinna 	}
208937c30d7SJussi Kivilinna 
209937c30d7SJussi Kivilinna 	return err;
210937c30d7SJussi Kivilinna }
211937c30d7SJussi Kivilinna 
212e81792fbSJussi Kivilinna static unsigned int
213e81792fbSJussi Kivilinna __glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx,
214e81792fbSJussi Kivilinna 			  struct blkcipher_desc *desc,
215937c30d7SJussi Kivilinna 			  struct blkcipher_walk *walk)
216937c30d7SJussi Kivilinna {
217e81792fbSJussi Kivilinna 	void *ctx = crypto_blkcipher_ctx(desc->tfm);
218e81792fbSJussi Kivilinna 	const unsigned int bsize = 128 / 8;
219937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
220937c30d7SJussi Kivilinna 	u128 *src = (u128 *)walk->src.virt.addr;
221937c30d7SJussi Kivilinna 	u128 *dst = (u128 *)walk->dst.virt.addr;
222937c30d7SJussi Kivilinna 	u128 last_iv;
223e81792fbSJussi Kivilinna 	unsigned int num_blocks, func_bytes;
224e81792fbSJussi Kivilinna 	unsigned int i;
225937c30d7SJussi Kivilinna 
226937c30d7SJussi Kivilinna 	/* Start of the last block. */
227937c30d7SJussi Kivilinna 	src += nbytes / bsize - 1;
228937c30d7SJussi Kivilinna 	dst += nbytes / bsize - 1;
229937c30d7SJussi Kivilinna 
230937c30d7SJussi Kivilinna 	last_iv = *src;
231937c30d7SJussi Kivilinna 
232e81792fbSJussi Kivilinna 	for (i = 0; i < gctx->num_funcs; i++) {
233e81792fbSJussi Kivilinna 		num_blocks = gctx->funcs[i].num_blocks;
234e81792fbSJussi Kivilinna 		func_bytes = bsize * num_blocks;
235e81792fbSJussi Kivilinna 
236937c30d7SJussi Kivilinna 		/* Process multi-block batch */
237e81792fbSJussi Kivilinna 		if (nbytes >= func_bytes) {
238937c30d7SJussi Kivilinna 			do {
239e81792fbSJussi Kivilinna 				nbytes -= func_bytes - bsize;
240e81792fbSJussi Kivilinna 				src -= num_blocks - 1;
241e81792fbSJussi Kivilinna 				dst -= num_blocks - 1;
242937c30d7SJussi Kivilinna 
243e81792fbSJussi Kivilinna 				gctx->funcs[i].fn_u.cbc(ctx, dst, src);
244937c30d7SJussi Kivilinna 
245937c30d7SJussi Kivilinna 				nbytes -= bsize;
246937c30d7SJussi Kivilinna 				if (nbytes < bsize)
247937c30d7SJussi Kivilinna 					goto done;
248937c30d7SJussi Kivilinna 
249937c30d7SJussi Kivilinna 				u128_xor(dst, dst, src - 1);
250937c30d7SJussi Kivilinna 				src -= 1;
251937c30d7SJussi Kivilinna 				dst -= 1;
252e81792fbSJussi Kivilinna 			} while (nbytes >= func_bytes);
253937c30d7SJussi Kivilinna 
254937c30d7SJussi Kivilinna 			if (nbytes < bsize)
255937c30d7SJussi Kivilinna 				goto done;
256937c30d7SJussi Kivilinna 		}
257937c30d7SJussi Kivilinna 	}
258937c30d7SJussi Kivilinna 
259937c30d7SJussi Kivilinna done:
260937c30d7SJussi Kivilinna 	u128_xor(dst, dst, (u128 *)walk->iv);
261937c30d7SJussi Kivilinna 	*(u128 *)walk->iv = last_iv;
262937c30d7SJussi Kivilinna 
263937c30d7SJussi Kivilinna 	return nbytes;
264937c30d7SJussi Kivilinna }
265937c30d7SJussi Kivilinna 
266e81792fbSJussi Kivilinna int glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx,
267e81792fbSJussi Kivilinna 			    struct blkcipher_desc *desc,
268e81792fbSJussi Kivilinna 			    struct scatterlist *dst,
269937c30d7SJussi Kivilinna 			    struct scatterlist *src, unsigned int nbytes)
270937c30d7SJussi Kivilinna {
271e81792fbSJussi Kivilinna 	const unsigned int bsize = 128 / 8;
272937c30d7SJussi Kivilinna 	bool fpu_enabled = false;
273937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
274937c30d7SJussi Kivilinna 	int err;
275937c30d7SJussi Kivilinna 
276937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
277937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
278937c30d7SJussi Kivilinna 
279937c30d7SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
280e81792fbSJussi Kivilinna 		fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
281e81792fbSJussi Kivilinna 					     desc, fpu_enabled, nbytes);
282e81792fbSJussi Kivilinna 		nbytes = __glue_cbc_decrypt_128bit(gctx, desc, &walk);
283937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
284937c30d7SJussi Kivilinna 	}
285937c30d7SJussi Kivilinna 
286e81792fbSJussi Kivilinna 	glue_fpu_end(fpu_enabled);
287937c30d7SJussi Kivilinna 	return err;
288937c30d7SJussi Kivilinna }
289937c30d7SJussi Kivilinna 
290937c30d7SJussi Kivilinna static inline void u128_to_be128(be128 *dst, const u128 *src)
291937c30d7SJussi Kivilinna {
292937c30d7SJussi Kivilinna 	dst->a = cpu_to_be64(src->a);
293937c30d7SJussi Kivilinna 	dst->b = cpu_to_be64(src->b);
294937c30d7SJussi Kivilinna }
295937c30d7SJussi Kivilinna 
296937c30d7SJussi Kivilinna static inline void be128_to_u128(u128 *dst, const be128 *src)
297937c30d7SJussi Kivilinna {
298937c30d7SJussi Kivilinna 	dst->a = be64_to_cpu(src->a);
299937c30d7SJussi Kivilinna 	dst->b = be64_to_cpu(src->b);
300937c30d7SJussi Kivilinna }
301937c30d7SJussi Kivilinna 
302937c30d7SJussi Kivilinna static inline void u128_inc(u128 *i)
303937c30d7SJussi Kivilinna {
304937c30d7SJussi Kivilinna 	i->b++;
305937c30d7SJussi Kivilinna 	if (!i->b)
306937c30d7SJussi Kivilinna 		i->a++;
307937c30d7SJussi Kivilinna }
308937c30d7SJussi Kivilinna 
309e81792fbSJussi Kivilinna static void glue_ctr_crypt_final_128bit(const common_glue_ctr_func_t fn_ctr,
310e81792fbSJussi Kivilinna 					struct blkcipher_desc *desc,
311937c30d7SJussi Kivilinna 					struct blkcipher_walk *walk)
312937c30d7SJussi Kivilinna {
313e81792fbSJussi Kivilinna 	void *ctx = crypto_blkcipher_ctx(desc->tfm);
314e81792fbSJussi Kivilinna 	u8 *src = (u8 *)walk->src.virt.addr;
315e81792fbSJussi Kivilinna 	u8 *dst = (u8 *)walk->dst.virt.addr;
316937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
317e81792fbSJussi Kivilinna 	u128 ctrblk;
318e81792fbSJussi Kivilinna 	u128 tmp;
319937c30d7SJussi Kivilinna 
320e81792fbSJussi Kivilinna 	be128_to_u128(&ctrblk, (be128 *)walk->iv);
321937c30d7SJussi Kivilinna 
322e81792fbSJussi Kivilinna 	memcpy(&tmp, src, nbytes);
323e81792fbSJussi Kivilinna 	fn_ctr(ctx, &tmp, &tmp, &ctrblk);
324e81792fbSJussi Kivilinna 	memcpy(dst, &tmp, nbytes);
325e81792fbSJussi Kivilinna 
326e81792fbSJussi Kivilinna 	u128_to_be128((be128 *)walk->iv, &ctrblk);
327937c30d7SJussi Kivilinna }
328937c30d7SJussi Kivilinna 
329e81792fbSJussi Kivilinna static unsigned int __glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx,
330e81792fbSJussi Kivilinna 					    struct blkcipher_desc *desc,
331937c30d7SJussi Kivilinna 					    struct blkcipher_walk *walk)
332937c30d7SJussi Kivilinna {
333e81792fbSJussi Kivilinna 	const unsigned int bsize = 128 / 8;
334e81792fbSJussi Kivilinna 	void *ctx = crypto_blkcipher_ctx(desc->tfm);
335937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
336937c30d7SJussi Kivilinna 	u128 *src = (u128 *)walk->src.virt.addr;
337937c30d7SJussi Kivilinna 	u128 *dst = (u128 *)walk->dst.virt.addr;
338937c30d7SJussi Kivilinna 	u128 ctrblk;
339e81792fbSJussi Kivilinna 	unsigned int num_blocks, func_bytes;
340e81792fbSJussi Kivilinna 	unsigned int i;
341937c30d7SJussi Kivilinna 
342937c30d7SJussi Kivilinna 	be128_to_u128(&ctrblk, (be128 *)walk->iv);
343937c30d7SJussi Kivilinna 
344937c30d7SJussi Kivilinna 	/* Process multi-block batch */
345e81792fbSJussi Kivilinna 	for (i = 0; i < gctx->num_funcs; i++) {
346e81792fbSJussi Kivilinna 		num_blocks = gctx->funcs[i].num_blocks;
347e81792fbSJussi Kivilinna 		func_bytes = bsize * num_blocks;
348e81792fbSJussi Kivilinna 
349e81792fbSJussi Kivilinna 		if (nbytes >= func_bytes) {
350937c30d7SJussi Kivilinna 			do {
351e81792fbSJussi Kivilinna 				gctx->funcs[i].fn_u.ctr(ctx, dst, src, &ctrblk);
352937c30d7SJussi Kivilinna 
353e81792fbSJussi Kivilinna 				src += num_blocks;
354e81792fbSJussi Kivilinna 				dst += num_blocks;
355e81792fbSJussi Kivilinna 				nbytes -= func_bytes;
356e81792fbSJussi Kivilinna 			} while (nbytes >= func_bytes);
357937c30d7SJussi Kivilinna 
358937c30d7SJussi Kivilinna 			if (nbytes < bsize)
359937c30d7SJussi Kivilinna 				goto done;
360937c30d7SJussi Kivilinna 		}
361e81792fbSJussi Kivilinna 	}
362937c30d7SJussi Kivilinna 
363937c30d7SJussi Kivilinna done:
364937c30d7SJussi Kivilinna 	u128_to_be128((be128 *)walk->iv, &ctrblk);
365937c30d7SJussi Kivilinna 	return nbytes;
366937c30d7SJussi Kivilinna }
367937c30d7SJussi Kivilinna 
368e81792fbSJussi Kivilinna int glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx,
369e81792fbSJussi Kivilinna 			  struct blkcipher_desc *desc, struct scatterlist *dst,
370937c30d7SJussi Kivilinna 			  struct scatterlist *src, unsigned int nbytes)
371937c30d7SJussi Kivilinna {
372e81792fbSJussi Kivilinna 	const unsigned int bsize = 128 / 8;
373937c30d7SJussi Kivilinna 	bool fpu_enabled = false;
374937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
375937c30d7SJussi Kivilinna 	int err;
376937c30d7SJussi Kivilinna 
377937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
378e81792fbSJussi Kivilinna 	err = blkcipher_walk_virt_block(desc, &walk, bsize);
379937c30d7SJussi Kivilinna 
380e81792fbSJussi Kivilinna 	while ((nbytes = walk.nbytes) >= bsize) {
381e81792fbSJussi Kivilinna 		fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
382e81792fbSJussi Kivilinna 					     desc, fpu_enabled, nbytes);
383e81792fbSJussi Kivilinna 		nbytes = __glue_ctr_crypt_128bit(gctx, desc, &walk);
384937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
385937c30d7SJussi Kivilinna 	}
386937c30d7SJussi Kivilinna 
387e81792fbSJussi Kivilinna 	glue_fpu_end(fpu_enabled);
388937c30d7SJussi Kivilinna 
389937c30d7SJussi Kivilinna 	if (walk.nbytes) {
390e81792fbSJussi Kivilinna 		glue_ctr_crypt_final_128bit(
391e81792fbSJussi Kivilinna 			gctx->funcs[gctx->num_funcs - 1].fn_u.ctr, desc, &walk);
392937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, 0);
393937c30d7SJussi Kivilinna 	}
394937c30d7SJussi Kivilinna 
395937c30d7SJussi Kivilinna 	return err;
396937c30d7SJussi Kivilinna }
397937c30d7SJussi Kivilinna 
398e81792fbSJussi Kivilinna static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
399e81792fbSJussi Kivilinna {
400e81792fbSJussi Kivilinna 	u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
401e81792fbSJussi Kivilinna 	unsigned int j;
402e81792fbSJussi Kivilinna 
403e81792fbSJussi Kivilinna 	for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++)
404e81792fbSJussi Kivilinna 		ivs[j] = src[j];
405e81792fbSJussi Kivilinna 
406e81792fbSJussi Kivilinna 	serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
407e81792fbSJussi Kivilinna 
408e81792fbSJussi Kivilinna 	for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++)
409e81792fbSJussi Kivilinna 		u128_xor(dst + (j + 1), dst + (j + 1), ivs + j);
410e81792fbSJussi Kivilinna }
411e81792fbSJussi Kivilinna 
412e81792fbSJussi Kivilinna static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv)
413e81792fbSJussi Kivilinna {
414e81792fbSJussi Kivilinna 	be128 ctrblk;
415e81792fbSJussi Kivilinna 
416e81792fbSJussi Kivilinna 	u128_to_be128(&ctrblk, iv);
417e81792fbSJussi Kivilinna 	u128_inc(iv);
418e81792fbSJussi Kivilinna 
419e81792fbSJussi Kivilinna 	__serpent_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk);
420e81792fbSJussi Kivilinna 	u128_xor(dst, src, (u128 *)&ctrblk);
421e81792fbSJussi Kivilinna }
422e81792fbSJussi Kivilinna 
423e81792fbSJussi Kivilinna static void serpent_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src,
424e81792fbSJussi Kivilinna 				   u128 *iv)
425e81792fbSJussi Kivilinna {
426e81792fbSJussi Kivilinna 	be128 ctrblks[SERPENT_PARALLEL_BLOCKS];
427e81792fbSJussi Kivilinna 	unsigned int i;
428e81792fbSJussi Kivilinna 
429e81792fbSJussi Kivilinna 	for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
430e81792fbSJussi Kivilinna 		if (dst != src)
431e81792fbSJussi Kivilinna 			dst[i] = src[i];
432e81792fbSJussi Kivilinna 
433e81792fbSJussi Kivilinna 		u128_to_be128(&ctrblks[i], iv);
434e81792fbSJussi Kivilinna 		u128_inc(iv);
435e81792fbSJussi Kivilinna 	}
436e81792fbSJussi Kivilinna 
437e81792fbSJussi Kivilinna 	serpent_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks);
438e81792fbSJussi Kivilinna }
439e81792fbSJussi Kivilinna 
440e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_enc = {
441e81792fbSJussi Kivilinna 	.num_funcs = 2,
442e81792fbSJussi Kivilinna 	.fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
443e81792fbSJussi Kivilinna 
444e81792fbSJussi Kivilinna 	.funcs = { {
445e81792fbSJussi Kivilinna 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
446e81792fbSJussi Kivilinna 		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_enc_blk_xway) }
447e81792fbSJussi Kivilinna 	}, {
448e81792fbSJussi Kivilinna 		.num_blocks = 1,
449e81792fbSJussi Kivilinna 		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) }
450e81792fbSJussi Kivilinna 	} }
451e81792fbSJussi Kivilinna };
452e81792fbSJussi Kivilinna 
453e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_ctr = {
454e81792fbSJussi Kivilinna 	.num_funcs = 2,
455e81792fbSJussi Kivilinna 	.fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
456e81792fbSJussi Kivilinna 
457e81792fbSJussi Kivilinna 	.funcs = { {
458e81792fbSJussi Kivilinna 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
459e81792fbSJussi Kivilinna 		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr_xway) }
460e81792fbSJussi Kivilinna 	}, {
461e81792fbSJussi Kivilinna 		.num_blocks = 1,
462e81792fbSJussi Kivilinna 		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr) }
463e81792fbSJussi Kivilinna 	} }
464e81792fbSJussi Kivilinna };
465e81792fbSJussi Kivilinna 
466e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec = {
467e81792fbSJussi Kivilinna 	.num_funcs = 2,
468e81792fbSJussi Kivilinna 	.fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
469e81792fbSJussi Kivilinna 
470e81792fbSJussi Kivilinna 	.funcs = { {
471e81792fbSJussi Kivilinna 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
472e81792fbSJussi Kivilinna 		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_dec_blk_xway) }
473e81792fbSJussi Kivilinna 	}, {
474e81792fbSJussi Kivilinna 		.num_blocks = 1,
475e81792fbSJussi Kivilinna 		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) }
476e81792fbSJussi Kivilinna 	} }
477e81792fbSJussi Kivilinna };
478e81792fbSJussi Kivilinna 
479e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec_cbc = {
480e81792fbSJussi Kivilinna 	.num_funcs = 2,
481e81792fbSJussi Kivilinna 	.fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
482e81792fbSJussi Kivilinna 
483e81792fbSJussi Kivilinna 	.funcs = { {
484e81792fbSJussi Kivilinna 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
485e81792fbSJussi Kivilinna 		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_decrypt_cbc_xway) }
486e81792fbSJussi Kivilinna 	}, {
487e81792fbSJussi Kivilinna 		.num_blocks = 1,
488e81792fbSJussi Kivilinna 		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) }
489e81792fbSJussi Kivilinna 	} }
490e81792fbSJussi Kivilinna };
491e81792fbSJussi Kivilinna 
492e81792fbSJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
493e81792fbSJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
494e81792fbSJussi Kivilinna {
495e81792fbSJussi Kivilinna 	return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes);
496e81792fbSJussi Kivilinna }
497e81792fbSJussi Kivilinna 
498e81792fbSJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
499e81792fbSJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
500e81792fbSJussi Kivilinna {
501e81792fbSJussi Kivilinna 	return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes);
502e81792fbSJussi Kivilinna }
503e81792fbSJussi Kivilinna 
504e81792fbSJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
505e81792fbSJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
506e81792fbSJussi Kivilinna {
507e81792fbSJussi Kivilinna 	return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc,
508e81792fbSJussi Kivilinna 				     dst, src, nbytes);
509e81792fbSJussi Kivilinna }
510e81792fbSJussi Kivilinna 
511e81792fbSJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
512e81792fbSJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
513e81792fbSJussi Kivilinna {
514e81792fbSJussi Kivilinna 	return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src,
515e81792fbSJussi Kivilinna 				       nbytes);
516e81792fbSJussi Kivilinna }
517e81792fbSJussi Kivilinna 
518e81792fbSJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
519e81792fbSJussi Kivilinna 		     struct scatterlist *src, unsigned int nbytes)
520e81792fbSJussi Kivilinna {
521e81792fbSJussi Kivilinna 	return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes);
522e81792fbSJussi Kivilinna }
523e81792fbSJussi Kivilinna 
524e81792fbSJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
525e81792fbSJussi Kivilinna {
526e81792fbSJussi Kivilinna 	return glue_fpu_begin(SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS,
527e81792fbSJussi Kivilinna 			      NULL, fpu_enabled, nbytes);
528e81792fbSJussi Kivilinna }
529e81792fbSJussi Kivilinna 
530e81792fbSJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled)
531e81792fbSJussi Kivilinna {
532e81792fbSJussi Kivilinna 	glue_fpu_end(fpu_enabled);
533e81792fbSJussi Kivilinna }
534e81792fbSJussi Kivilinna 
53518482053SJussi Kivilinna struct crypt_priv {
53618482053SJussi Kivilinna 	struct serpent_ctx *ctx;
53718482053SJussi Kivilinna 	bool fpu_enabled;
53818482053SJussi Kivilinna };
53918482053SJussi Kivilinna 
54018482053SJussi Kivilinna static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
54118482053SJussi Kivilinna {
54218482053SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
54318482053SJussi Kivilinna 	struct crypt_priv *ctx = priv;
54418482053SJussi Kivilinna 	int i;
54518482053SJussi Kivilinna 
54618482053SJussi Kivilinna 	ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
54718482053SJussi Kivilinna 
54818482053SJussi Kivilinna 	if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
54918482053SJussi Kivilinna 		serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst);
55018482053SJussi Kivilinna 		return;
55118482053SJussi Kivilinna 	}
55218482053SJussi Kivilinna 
55318482053SJussi Kivilinna 	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
55418482053SJussi Kivilinna 		__serpent_encrypt(ctx->ctx, srcdst, srcdst);
55518482053SJussi Kivilinna }
55618482053SJussi Kivilinna 
55718482053SJussi Kivilinna static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
55818482053SJussi Kivilinna {
55918482053SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
56018482053SJussi Kivilinna 	struct crypt_priv *ctx = priv;
56118482053SJussi Kivilinna 	int i;
56218482053SJussi Kivilinna 
56318482053SJussi Kivilinna 	ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
56418482053SJussi Kivilinna 
56518482053SJussi Kivilinna 	if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
56618482053SJussi Kivilinna 		serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst);
56718482053SJussi Kivilinna 		return;
56818482053SJussi Kivilinna 	}
56918482053SJussi Kivilinna 
57018482053SJussi Kivilinna 	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
57118482053SJussi Kivilinna 		__serpent_decrypt(ctx->ctx, srcdst, srcdst);
57218482053SJussi Kivilinna }
57318482053SJussi Kivilinna 
57418482053SJussi Kivilinna struct serpent_lrw_ctx {
57518482053SJussi Kivilinna 	struct lrw_table_ctx lrw_table;
57618482053SJussi Kivilinna 	struct serpent_ctx serpent_ctx;
57718482053SJussi Kivilinna };
57818482053SJussi Kivilinna 
57918482053SJussi Kivilinna static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
58018482053SJussi Kivilinna 			      unsigned int keylen)
58118482053SJussi Kivilinna {
58218482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
58318482053SJussi Kivilinna 	int err;
58418482053SJussi Kivilinna 
58518482053SJussi Kivilinna 	err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
58618482053SJussi Kivilinna 							SERPENT_BLOCK_SIZE);
58718482053SJussi Kivilinna 	if (err)
58818482053SJussi Kivilinna 		return err;
58918482053SJussi Kivilinna 
59018482053SJussi Kivilinna 	return lrw_init_table(&ctx->lrw_table, key + keylen -
59118482053SJussi Kivilinna 						SERPENT_BLOCK_SIZE);
59218482053SJussi Kivilinna }
59318482053SJussi Kivilinna 
59418482053SJussi Kivilinna static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
59518482053SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
59618482053SJussi Kivilinna {
59718482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
59818482053SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
59918482053SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
60018482053SJussi Kivilinna 		.ctx = &ctx->serpent_ctx,
60118482053SJussi Kivilinna 		.fpu_enabled = false,
60218482053SJussi Kivilinna 	};
60318482053SJussi Kivilinna 	struct lrw_crypt_req req = {
60418482053SJussi Kivilinna 		.tbuf = buf,
60518482053SJussi Kivilinna 		.tbuflen = sizeof(buf),
60618482053SJussi Kivilinna 
60718482053SJussi Kivilinna 		.table_ctx = &ctx->lrw_table,
60818482053SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
60918482053SJussi Kivilinna 		.crypt_fn = encrypt_callback,
61018482053SJussi Kivilinna 	};
61118482053SJussi Kivilinna 	int ret;
61218482053SJussi Kivilinna 
613d3564338SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
61418482053SJussi Kivilinna 	ret = lrw_crypt(desc, dst, src, nbytes, &req);
61518482053SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
61618482053SJussi Kivilinna 
61718482053SJussi Kivilinna 	return ret;
61818482053SJussi Kivilinna }
61918482053SJussi Kivilinna 
62018482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
62118482053SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
62218482053SJussi Kivilinna {
62318482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
62418482053SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
62518482053SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
62618482053SJussi Kivilinna 		.ctx = &ctx->serpent_ctx,
62718482053SJussi Kivilinna 		.fpu_enabled = false,
62818482053SJussi Kivilinna 	};
62918482053SJussi Kivilinna 	struct lrw_crypt_req req = {
63018482053SJussi Kivilinna 		.tbuf = buf,
63118482053SJussi Kivilinna 		.tbuflen = sizeof(buf),
63218482053SJussi Kivilinna 
63318482053SJussi Kivilinna 		.table_ctx = &ctx->lrw_table,
63418482053SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
63518482053SJussi Kivilinna 		.crypt_fn = decrypt_callback,
63618482053SJussi Kivilinna 	};
63718482053SJussi Kivilinna 	int ret;
63818482053SJussi Kivilinna 
639d3564338SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
64018482053SJussi Kivilinna 	ret = lrw_crypt(desc, dst, src, nbytes, &req);
64118482053SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
64218482053SJussi Kivilinna 
64318482053SJussi Kivilinna 	return ret;
64418482053SJussi Kivilinna }
64518482053SJussi Kivilinna 
64618482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm)
64718482053SJussi Kivilinna {
64818482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
64918482053SJussi Kivilinna 
65018482053SJussi Kivilinna 	lrw_free_table(&ctx->lrw_table);
65118482053SJussi Kivilinna }
65218482053SJussi Kivilinna 
6535962f8b6SJussi Kivilinna struct serpent_xts_ctx {
6545962f8b6SJussi Kivilinna 	struct serpent_ctx tweak_ctx;
6555962f8b6SJussi Kivilinna 	struct serpent_ctx crypt_ctx;
6565962f8b6SJussi Kivilinna };
6575962f8b6SJussi Kivilinna 
6585962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
6595962f8b6SJussi Kivilinna 			      unsigned int keylen)
6605962f8b6SJussi Kivilinna {
6615962f8b6SJussi Kivilinna 	struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
6625962f8b6SJussi Kivilinna 	u32 *flags = &tfm->crt_flags;
6635962f8b6SJussi Kivilinna 	int err;
6645962f8b6SJussi Kivilinna 
6655962f8b6SJussi Kivilinna 	/* key consists of keys of equal size concatenated, therefore
6665962f8b6SJussi Kivilinna 	 * the length must be even
6675962f8b6SJussi Kivilinna 	 */
6685962f8b6SJussi Kivilinna 	if (keylen % 2) {
6695962f8b6SJussi Kivilinna 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
6705962f8b6SJussi Kivilinna 		return -EINVAL;
6715962f8b6SJussi Kivilinna 	}
6725962f8b6SJussi Kivilinna 
6735962f8b6SJussi Kivilinna 	/* first half of xts-key is for crypt */
6745962f8b6SJussi Kivilinna 	err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
6755962f8b6SJussi Kivilinna 	if (err)
6765962f8b6SJussi Kivilinna 		return err;
6775962f8b6SJussi Kivilinna 
6785962f8b6SJussi Kivilinna 	/* second half of xts-key is for tweak */
6795962f8b6SJussi Kivilinna 	return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
6805962f8b6SJussi Kivilinna }
6815962f8b6SJussi Kivilinna 
6825962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
6835962f8b6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
6845962f8b6SJussi Kivilinna {
6855962f8b6SJussi Kivilinna 	struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
6865962f8b6SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
6875962f8b6SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
6885962f8b6SJussi Kivilinna 		.ctx = &ctx->crypt_ctx,
6895962f8b6SJussi Kivilinna 		.fpu_enabled = false,
6905962f8b6SJussi Kivilinna 	};
6915962f8b6SJussi Kivilinna 	struct xts_crypt_req req = {
6925962f8b6SJussi Kivilinna 		.tbuf = buf,
6935962f8b6SJussi Kivilinna 		.tbuflen = sizeof(buf),
6945962f8b6SJussi Kivilinna 
6955962f8b6SJussi Kivilinna 		.tweak_ctx = &ctx->tweak_ctx,
6965962f8b6SJussi Kivilinna 		.tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
6975962f8b6SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
6985962f8b6SJussi Kivilinna 		.crypt_fn = encrypt_callback,
6995962f8b6SJussi Kivilinna 	};
7005962f8b6SJussi Kivilinna 	int ret;
7015962f8b6SJussi Kivilinna 
702d3564338SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
7035962f8b6SJussi Kivilinna 	ret = xts_crypt(desc, dst, src, nbytes, &req);
7045962f8b6SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
7055962f8b6SJussi Kivilinna 
7065962f8b6SJussi Kivilinna 	return ret;
7075962f8b6SJussi Kivilinna }
7085962f8b6SJussi Kivilinna 
7095962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
7105962f8b6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
7115962f8b6SJussi Kivilinna {
7125962f8b6SJussi Kivilinna 	struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
7135962f8b6SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
7145962f8b6SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
7155962f8b6SJussi Kivilinna 		.ctx = &ctx->crypt_ctx,
7165962f8b6SJussi Kivilinna 		.fpu_enabled = false,
7175962f8b6SJussi Kivilinna 	};
7185962f8b6SJussi Kivilinna 	struct xts_crypt_req req = {
7195962f8b6SJussi Kivilinna 		.tbuf = buf,
7205962f8b6SJussi Kivilinna 		.tbuflen = sizeof(buf),
7215962f8b6SJussi Kivilinna 
7225962f8b6SJussi Kivilinna 		.tweak_ctx = &ctx->tweak_ctx,
7235962f8b6SJussi Kivilinna 		.tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
7245962f8b6SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
7255962f8b6SJussi Kivilinna 		.crypt_fn = decrypt_callback,
7265962f8b6SJussi Kivilinna 	};
7275962f8b6SJussi Kivilinna 	int ret;
7285962f8b6SJussi Kivilinna 
729d3564338SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
7305962f8b6SJussi Kivilinna 	ret = xts_crypt(desc, dst, src, nbytes, &req);
7315962f8b6SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
7325962f8b6SJussi Kivilinna 
7335962f8b6SJussi Kivilinna 	return ret;
7345962f8b6SJussi Kivilinna }
7355962f8b6SJussi Kivilinna 
73635474c3bSJussi Kivilinna static struct crypto_alg serpent_algs[10] = { {
73735474c3bSJussi Kivilinna 	.cra_name		= "__ecb-serpent-sse2",
73835474c3bSJussi Kivilinna 	.cra_driver_name	= "__driver-ecb-serpent-sse2",
73935474c3bSJussi Kivilinna 	.cra_priority		= 0,
74035474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
74135474c3bSJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
74235474c3bSJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_ctx),
74335474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
74435474c3bSJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
74535474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
74635474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[0].cra_list),
74735474c3bSJussi Kivilinna 	.cra_u = {
74835474c3bSJussi Kivilinna 		.blkcipher = {
74935474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
75035474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
75135474c3bSJussi Kivilinna 			.setkey		= serpent_setkey,
75235474c3bSJussi Kivilinna 			.encrypt	= ecb_encrypt,
75335474c3bSJussi Kivilinna 			.decrypt	= ecb_decrypt,
75435474c3bSJussi Kivilinna 		},
75535474c3bSJussi Kivilinna 	},
75635474c3bSJussi Kivilinna }, {
75735474c3bSJussi Kivilinna 	.cra_name		= "__cbc-serpent-sse2",
75835474c3bSJussi Kivilinna 	.cra_driver_name	= "__driver-cbc-serpent-sse2",
75935474c3bSJussi Kivilinna 	.cra_priority		= 0,
76035474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
76135474c3bSJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
76235474c3bSJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_ctx),
76335474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
76435474c3bSJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
76535474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
76635474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[1].cra_list),
76735474c3bSJussi Kivilinna 	.cra_u = {
76835474c3bSJussi Kivilinna 		.blkcipher = {
76935474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
77035474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
77135474c3bSJussi Kivilinna 			.setkey		= serpent_setkey,
77235474c3bSJussi Kivilinna 			.encrypt	= cbc_encrypt,
77335474c3bSJussi Kivilinna 			.decrypt	= cbc_decrypt,
77435474c3bSJussi Kivilinna 		},
77535474c3bSJussi Kivilinna 	},
77635474c3bSJussi Kivilinna }, {
77735474c3bSJussi Kivilinna 	.cra_name		= "__ctr-serpent-sse2",
77835474c3bSJussi Kivilinna 	.cra_driver_name	= "__driver-ctr-serpent-sse2",
77935474c3bSJussi Kivilinna 	.cra_priority		= 0,
78035474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
78135474c3bSJussi Kivilinna 	.cra_blocksize		= 1,
78235474c3bSJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_ctx),
78335474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
78435474c3bSJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
78535474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
78635474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[2].cra_list),
78735474c3bSJussi Kivilinna 	.cra_u = {
78835474c3bSJussi Kivilinna 		.blkcipher = {
78935474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
79035474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
79135474c3bSJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
79235474c3bSJussi Kivilinna 			.setkey		= serpent_setkey,
79335474c3bSJussi Kivilinna 			.encrypt	= ctr_crypt,
79435474c3bSJussi Kivilinna 			.decrypt	= ctr_crypt,
79535474c3bSJussi Kivilinna 		},
79635474c3bSJussi Kivilinna 	},
79735474c3bSJussi Kivilinna }, {
79835474c3bSJussi Kivilinna 	.cra_name		= "__lrw-serpent-sse2",
79935474c3bSJussi Kivilinna 	.cra_driver_name	= "__driver-lrw-serpent-sse2",
80035474c3bSJussi Kivilinna 	.cra_priority		= 0,
80135474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
80235474c3bSJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
80335474c3bSJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_lrw_ctx),
80435474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
80535474c3bSJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
80635474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
80735474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[3].cra_list),
80835474c3bSJussi Kivilinna 	.cra_exit		= lrw_exit_tfm,
80935474c3bSJussi Kivilinna 	.cra_u = {
81035474c3bSJussi Kivilinna 		.blkcipher = {
81135474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE +
81235474c3bSJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
81335474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE +
81435474c3bSJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
81535474c3bSJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
81635474c3bSJussi Kivilinna 			.setkey		= lrw_serpent_setkey,
81735474c3bSJussi Kivilinna 			.encrypt	= lrw_encrypt,
81835474c3bSJussi Kivilinna 			.decrypt	= lrw_decrypt,
81935474c3bSJussi Kivilinna 		},
82035474c3bSJussi Kivilinna 	},
82135474c3bSJussi Kivilinna }, {
82235474c3bSJussi Kivilinna 	.cra_name		= "__xts-serpent-sse2",
82335474c3bSJussi Kivilinna 	.cra_driver_name	= "__driver-xts-serpent-sse2",
82435474c3bSJussi Kivilinna 	.cra_priority		= 0,
82535474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
82635474c3bSJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
82735474c3bSJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_xts_ctx),
82835474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
82935474c3bSJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
83035474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
83135474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[4].cra_list),
83235474c3bSJussi Kivilinna 	.cra_u = {
83335474c3bSJussi Kivilinna 		.blkcipher = {
83435474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
83535474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE * 2,
83635474c3bSJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
83735474c3bSJussi Kivilinna 			.setkey		= xts_serpent_setkey,
83835474c3bSJussi Kivilinna 			.encrypt	= xts_encrypt,
83935474c3bSJussi Kivilinna 			.decrypt	= xts_decrypt,
84035474c3bSJussi Kivilinna 		},
84135474c3bSJussi Kivilinna 	},
84235474c3bSJussi Kivilinna }, {
84335474c3bSJussi Kivilinna 	.cra_name		= "ecb(serpent)",
84435474c3bSJussi Kivilinna 	.cra_driver_name	= "ecb-serpent-sse2",
84535474c3bSJussi Kivilinna 	.cra_priority		= 400,
84635474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
84735474c3bSJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
848ffaf9156SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
84935474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
85035474c3bSJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
85135474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
85235474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[5].cra_list),
853435d3e51SJussi Kivilinna 	.cra_init		= ablk_init,
85435474c3bSJussi Kivilinna 	.cra_exit		= ablk_exit,
85535474c3bSJussi Kivilinna 	.cra_u = {
85635474c3bSJussi Kivilinna 		.ablkcipher = {
85735474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
85835474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
85935474c3bSJussi Kivilinna 			.setkey		= ablk_set_key,
86035474c3bSJussi Kivilinna 			.encrypt	= ablk_encrypt,
86135474c3bSJussi Kivilinna 			.decrypt	= ablk_decrypt,
86235474c3bSJussi Kivilinna 		},
86335474c3bSJussi Kivilinna 	},
86435474c3bSJussi Kivilinna }, {
86535474c3bSJussi Kivilinna 	.cra_name		= "cbc(serpent)",
86635474c3bSJussi Kivilinna 	.cra_driver_name	= "cbc-serpent-sse2",
86735474c3bSJussi Kivilinna 	.cra_priority		= 400,
86835474c3bSJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
86935474c3bSJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
870ffaf9156SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
87135474c3bSJussi Kivilinna 	.cra_alignmask		= 0,
87235474c3bSJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
87335474c3bSJussi Kivilinna 	.cra_module		= THIS_MODULE,
87435474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[6].cra_list),
875435d3e51SJussi Kivilinna 	.cra_init		= ablk_init,
87635474c3bSJussi Kivilinna 	.cra_exit		= ablk_exit,
87735474c3bSJussi Kivilinna 	.cra_u = {
87835474c3bSJussi Kivilinna 		.ablkcipher = {
87935474c3bSJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
88035474c3bSJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
88135474c3bSJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
88235474c3bSJussi Kivilinna 			.setkey		= ablk_set_key,
88335474c3bSJussi Kivilinna 			.encrypt	= __ablk_encrypt,
88435474c3bSJussi Kivilinna 			.decrypt	= ablk_decrypt,
88535474c3bSJussi Kivilinna 		},
88635474c3bSJussi Kivilinna 	},
88735474c3bSJussi Kivilinna }, {
888937c30d7SJussi Kivilinna 	.cra_name		= "ctr(serpent)",
889937c30d7SJussi Kivilinna 	.cra_driver_name	= "ctr-serpent-sse2",
890937c30d7SJussi Kivilinna 	.cra_priority		= 400,
891937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
892937c30d7SJussi Kivilinna 	.cra_blocksize		= 1,
893ffaf9156SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
894937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
895937c30d7SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
896937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
89735474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[7].cra_list),
898435d3e51SJussi Kivilinna 	.cra_init		= ablk_init,
899937c30d7SJussi Kivilinna 	.cra_exit		= ablk_exit,
900937c30d7SJussi Kivilinna 	.cra_u = {
901937c30d7SJussi Kivilinna 		.ablkcipher = {
902937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
903937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
904937c30d7SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
905937c30d7SJussi Kivilinna 			.setkey		= ablk_set_key,
906937c30d7SJussi Kivilinna 			.encrypt	= ablk_encrypt,
907937c30d7SJussi Kivilinna 			.decrypt	= ablk_encrypt,
908937c30d7SJussi Kivilinna 			.geniv		= "chainiv",
909937c30d7SJussi Kivilinna 		},
910937c30d7SJussi Kivilinna 	},
91135474c3bSJussi Kivilinna }, {
91218482053SJussi Kivilinna 	.cra_name		= "lrw(serpent)",
91318482053SJussi Kivilinna 	.cra_driver_name	= "lrw-serpent-sse2",
91418482053SJussi Kivilinna 	.cra_priority		= 400,
91518482053SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
91618482053SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
917ffaf9156SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
91818482053SJussi Kivilinna 	.cra_alignmask		= 0,
91918482053SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
92018482053SJussi Kivilinna 	.cra_module		= THIS_MODULE,
92135474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[8].cra_list),
922435d3e51SJussi Kivilinna 	.cra_init		= ablk_init,
92318482053SJussi Kivilinna 	.cra_exit		= ablk_exit,
92418482053SJussi Kivilinna 	.cra_u = {
92518482053SJussi Kivilinna 		.ablkcipher = {
92618482053SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE +
92718482053SJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
92818482053SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE +
92918482053SJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
93018482053SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
93118482053SJussi Kivilinna 			.setkey		= ablk_set_key,
93218482053SJussi Kivilinna 			.encrypt	= ablk_encrypt,
93318482053SJussi Kivilinna 			.decrypt	= ablk_decrypt,
93418482053SJussi Kivilinna 		},
93518482053SJussi Kivilinna 	},
93635474c3bSJussi Kivilinna }, {
9375962f8b6SJussi Kivilinna 	.cra_name		= "xts(serpent)",
9385962f8b6SJussi Kivilinna 	.cra_driver_name	= "xts-serpent-sse2",
9395962f8b6SJussi Kivilinna 	.cra_priority		= 400,
9405962f8b6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
9415962f8b6SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
942ffaf9156SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_helper_ctx),
9435962f8b6SJussi Kivilinna 	.cra_alignmask		= 0,
9445962f8b6SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
9455962f8b6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
94635474c3bSJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(serpent_algs[9].cra_list),
947435d3e51SJussi Kivilinna 	.cra_init		= ablk_init,
9485962f8b6SJussi Kivilinna 	.cra_exit		= ablk_exit,
9495962f8b6SJussi Kivilinna 	.cra_u = {
9505962f8b6SJussi Kivilinna 		.ablkcipher = {
9515962f8b6SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
9525962f8b6SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE * 2,
9535962f8b6SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
9545962f8b6SJussi Kivilinna 			.setkey		= ablk_set_key,
9555962f8b6SJussi Kivilinna 			.encrypt	= ablk_encrypt,
9565962f8b6SJussi Kivilinna 			.decrypt	= ablk_decrypt,
9575962f8b6SJussi Kivilinna 		},
9585962f8b6SJussi Kivilinna 	},
95935474c3bSJussi Kivilinna } };
9605962f8b6SJussi Kivilinna 
961937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void)
962937c30d7SJussi Kivilinna {
963937c30d7SJussi Kivilinna 	if (!cpu_has_xmm2) {
964937c30d7SJussi Kivilinna 		printk(KERN_INFO "SSE2 instructions are not detected.\n");
965937c30d7SJussi Kivilinna 		return -ENODEV;
966937c30d7SJussi Kivilinna 	}
967937c30d7SJussi Kivilinna 
96835474c3bSJussi Kivilinna 	return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
969937c30d7SJussi Kivilinna }
970937c30d7SJussi Kivilinna 
971937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void)
972937c30d7SJussi Kivilinna {
97335474c3bSJussi Kivilinna 	crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
974937c30d7SJussi Kivilinna }
975937c30d7SJussi Kivilinna 
976937c30d7SJussi Kivilinna module_init(serpent_sse2_init);
977937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit);
978937c30d7SJussi Kivilinna 
979937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized");
980937c30d7SJussi Kivilinna MODULE_LICENSE("GPL");
981937c30d7SJussi Kivilinna MODULE_ALIAS("serpent");
982