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>
45937c30d7SJussi Kivilinna #include <asm/serpent.h>
46937c30d7SJussi Kivilinna #include <crypto/scatterwalk.h>
47937c30d7SJussi Kivilinna #include <linux/workqueue.h>
48937c30d7SJussi Kivilinna #include <linux/spinlock.h>
49937c30d7SJussi Kivilinna 
5018482053SJussi Kivilinna #if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE)
5118482053SJussi Kivilinna #define HAS_LRW
5218482053SJussi Kivilinna #endif
5318482053SJussi Kivilinna 
545962f8b6SJussi Kivilinna #if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE)
555962f8b6SJussi Kivilinna #define HAS_XTS
565962f8b6SJussi Kivilinna #endif
575962f8b6SJussi Kivilinna 
58937c30d7SJussi Kivilinna struct async_serpent_ctx {
59937c30d7SJussi Kivilinna 	struct cryptd_ablkcipher *cryptd_tfm;
60937c30d7SJussi Kivilinna };
61937c30d7SJussi Kivilinna 
62937c30d7SJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
63937c30d7SJussi Kivilinna {
64937c30d7SJussi Kivilinna 	if (fpu_enabled)
65937c30d7SJussi Kivilinna 		return true;
66937c30d7SJussi Kivilinna 
67937c30d7SJussi Kivilinna 	/* SSE2 is only used when chunk to be processed is large enough, so
68937c30d7SJussi Kivilinna 	 * do not enable FPU until it is necessary.
69937c30d7SJussi Kivilinna 	 */
70937c30d7SJussi Kivilinna 	if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS)
71937c30d7SJussi Kivilinna 		return false;
72937c30d7SJussi Kivilinna 
73937c30d7SJussi Kivilinna 	kernel_fpu_begin();
74937c30d7SJussi Kivilinna 	return true;
75937c30d7SJussi Kivilinna }
76937c30d7SJussi Kivilinna 
77937c30d7SJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled)
78937c30d7SJussi Kivilinna {
79937c30d7SJussi Kivilinna 	if (fpu_enabled)
80937c30d7SJussi Kivilinna 		kernel_fpu_end();
81937c30d7SJussi Kivilinna }
82937c30d7SJussi Kivilinna 
83937c30d7SJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
84937c30d7SJussi Kivilinna 		     bool enc)
85937c30d7SJussi Kivilinna {
86937c30d7SJussi Kivilinna 	bool fpu_enabled = false;
87937c30d7SJussi Kivilinna 	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
88937c30d7SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
89937c30d7SJussi Kivilinna 	unsigned int nbytes;
90937c30d7SJussi Kivilinna 	int err;
91937c30d7SJussi Kivilinna 
92937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt(desc, walk);
93937c30d7SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
94937c30d7SJussi Kivilinna 
95937c30d7SJussi Kivilinna 	while ((nbytes = walk->nbytes)) {
96937c30d7SJussi Kivilinna 		u8 *wsrc = walk->src.virt.addr;
97937c30d7SJussi Kivilinna 		u8 *wdst = walk->dst.virt.addr;
98937c30d7SJussi Kivilinna 
99937c30d7SJussi Kivilinna 		fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
100937c30d7SJussi Kivilinna 
101937c30d7SJussi Kivilinna 		/* Process multi-block batch */
102937c30d7SJussi Kivilinna 		if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
103937c30d7SJussi Kivilinna 			do {
104937c30d7SJussi Kivilinna 				if (enc)
105937c30d7SJussi Kivilinna 					serpent_enc_blk_xway(ctx, wdst, wsrc);
106937c30d7SJussi Kivilinna 				else
107937c30d7SJussi Kivilinna 					serpent_dec_blk_xway(ctx, wdst, wsrc);
108937c30d7SJussi Kivilinna 
109937c30d7SJussi Kivilinna 				wsrc += bsize * SERPENT_PARALLEL_BLOCKS;
110937c30d7SJussi Kivilinna 				wdst += bsize * SERPENT_PARALLEL_BLOCKS;
111937c30d7SJussi Kivilinna 				nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
112937c30d7SJussi Kivilinna 			} while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
113937c30d7SJussi Kivilinna 
114937c30d7SJussi Kivilinna 			if (nbytes < bsize)
115937c30d7SJussi Kivilinna 				goto done;
116937c30d7SJussi Kivilinna 		}
117937c30d7SJussi Kivilinna 
118937c30d7SJussi Kivilinna 		/* Handle leftovers */
119937c30d7SJussi Kivilinna 		do {
120937c30d7SJussi Kivilinna 			if (enc)
121937c30d7SJussi Kivilinna 				__serpent_encrypt(ctx, wdst, wsrc);
122937c30d7SJussi Kivilinna 			else
123937c30d7SJussi Kivilinna 				__serpent_decrypt(ctx, wdst, wsrc);
124937c30d7SJussi Kivilinna 
125937c30d7SJussi Kivilinna 			wsrc += bsize;
126937c30d7SJussi Kivilinna 			wdst += bsize;
127937c30d7SJussi Kivilinna 			nbytes -= bsize;
128937c30d7SJussi Kivilinna 		} while (nbytes >= bsize);
129937c30d7SJussi Kivilinna 
130937c30d7SJussi Kivilinna done:
131937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, walk, nbytes);
132937c30d7SJussi Kivilinna 	}
133937c30d7SJussi Kivilinna 
134937c30d7SJussi Kivilinna 	serpent_fpu_end(fpu_enabled);
135937c30d7SJussi Kivilinna 	return err;
136937c30d7SJussi Kivilinna }
137937c30d7SJussi Kivilinna 
138937c30d7SJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
139937c30d7SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
140937c30d7SJussi Kivilinna {
141937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
142937c30d7SJussi Kivilinna 
143937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
144937c30d7SJussi Kivilinna 	return ecb_crypt(desc, &walk, true);
145937c30d7SJussi Kivilinna }
146937c30d7SJussi Kivilinna 
147937c30d7SJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
148937c30d7SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
149937c30d7SJussi Kivilinna {
150937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
151937c30d7SJussi Kivilinna 
152937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
153937c30d7SJussi Kivilinna 	return ecb_crypt(desc, &walk, false);
154937c30d7SJussi Kivilinna }
155937c30d7SJussi Kivilinna 
156937c30d7SJussi Kivilinna static struct crypto_alg blk_ecb_alg = {
157937c30d7SJussi Kivilinna 	.cra_name		= "__ecb-serpent-sse2",
158937c30d7SJussi Kivilinna 	.cra_driver_name	= "__driver-ecb-serpent-sse2",
159937c30d7SJussi Kivilinna 	.cra_priority		= 0,
160937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
161937c30d7SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
162937c30d7SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_ctx),
163937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
164937c30d7SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
165937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
166937c30d7SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(blk_ecb_alg.cra_list),
167937c30d7SJussi Kivilinna 	.cra_u = {
168937c30d7SJussi Kivilinna 		.blkcipher = {
169937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
170937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
171937c30d7SJussi Kivilinna 			.setkey		= serpent_setkey,
172937c30d7SJussi Kivilinna 			.encrypt	= ecb_encrypt,
173937c30d7SJussi Kivilinna 			.decrypt	= ecb_decrypt,
174937c30d7SJussi Kivilinna 		},
175937c30d7SJussi Kivilinna 	},
176937c30d7SJussi Kivilinna };
177937c30d7SJussi Kivilinna 
178937c30d7SJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
179937c30d7SJussi Kivilinna 				  struct blkcipher_walk *walk)
180937c30d7SJussi Kivilinna {
181937c30d7SJussi Kivilinna 	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
182937c30d7SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
183937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
184937c30d7SJussi Kivilinna 	u128 *src = (u128 *)walk->src.virt.addr;
185937c30d7SJussi Kivilinna 	u128 *dst = (u128 *)walk->dst.virt.addr;
186937c30d7SJussi Kivilinna 	u128 *iv = (u128 *)walk->iv;
187937c30d7SJussi Kivilinna 
188937c30d7SJussi Kivilinna 	do {
189937c30d7SJussi Kivilinna 		u128_xor(dst, src, iv);
190937c30d7SJussi Kivilinna 		__serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst);
191937c30d7SJussi Kivilinna 		iv = dst;
192937c30d7SJussi Kivilinna 
193937c30d7SJussi Kivilinna 		src += 1;
194937c30d7SJussi Kivilinna 		dst += 1;
195937c30d7SJussi Kivilinna 		nbytes -= bsize;
196937c30d7SJussi Kivilinna 	} while (nbytes >= bsize);
197937c30d7SJussi Kivilinna 
198937c30d7SJussi Kivilinna 	u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
199937c30d7SJussi Kivilinna 	return nbytes;
200937c30d7SJussi Kivilinna }
201937c30d7SJussi Kivilinna 
202937c30d7SJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
203937c30d7SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
204937c30d7SJussi Kivilinna {
205937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
206937c30d7SJussi Kivilinna 	int err;
207937c30d7SJussi Kivilinna 
208937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
209937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
210937c30d7SJussi Kivilinna 
211937c30d7SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
212937c30d7SJussi Kivilinna 		nbytes = __cbc_encrypt(desc, &walk);
213937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
214937c30d7SJussi Kivilinna 	}
215937c30d7SJussi Kivilinna 
216937c30d7SJussi Kivilinna 	return err;
217937c30d7SJussi Kivilinna }
218937c30d7SJussi Kivilinna 
219937c30d7SJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
220937c30d7SJussi Kivilinna 				  struct blkcipher_walk *walk)
221937c30d7SJussi Kivilinna {
222937c30d7SJussi Kivilinna 	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
223937c30d7SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
224937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
225937c30d7SJussi Kivilinna 	u128 *src = (u128 *)walk->src.virt.addr;
226937c30d7SJussi Kivilinna 	u128 *dst = (u128 *)walk->dst.virt.addr;
227937c30d7SJussi Kivilinna 	u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
228937c30d7SJussi Kivilinna 	u128 last_iv;
229937c30d7SJussi Kivilinna 	int i;
230937c30d7SJussi Kivilinna 
231937c30d7SJussi Kivilinna 	/* Start of the last block. */
232937c30d7SJussi Kivilinna 	src += nbytes / bsize - 1;
233937c30d7SJussi Kivilinna 	dst += nbytes / bsize - 1;
234937c30d7SJussi Kivilinna 
235937c30d7SJussi Kivilinna 	last_iv = *src;
236937c30d7SJussi Kivilinna 
237937c30d7SJussi Kivilinna 	/* Process multi-block batch */
238937c30d7SJussi Kivilinna 	if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
239937c30d7SJussi Kivilinna 		do {
240937c30d7SJussi Kivilinna 			nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1);
241937c30d7SJussi Kivilinna 			src -= SERPENT_PARALLEL_BLOCKS - 1;
242937c30d7SJussi Kivilinna 			dst -= SERPENT_PARALLEL_BLOCKS - 1;
243937c30d7SJussi Kivilinna 
244937c30d7SJussi Kivilinna 			for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
245937c30d7SJussi Kivilinna 				ivs[i] = src[i];
246937c30d7SJussi Kivilinna 
247937c30d7SJussi Kivilinna 			serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
248937c30d7SJussi Kivilinna 
249937c30d7SJussi Kivilinna 			for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
250937c30d7SJussi Kivilinna 				u128_xor(dst + (i + 1), dst + (i + 1), ivs + i);
251937c30d7SJussi Kivilinna 
252937c30d7SJussi Kivilinna 			nbytes -= bsize;
253937c30d7SJussi Kivilinna 			if (nbytes < bsize)
254937c30d7SJussi Kivilinna 				goto done;
255937c30d7SJussi Kivilinna 
256937c30d7SJussi Kivilinna 			u128_xor(dst, dst, src - 1);
257937c30d7SJussi Kivilinna 			src -= 1;
258937c30d7SJussi Kivilinna 			dst -= 1;
259937c30d7SJussi Kivilinna 		} while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
260937c30d7SJussi Kivilinna 
261937c30d7SJussi Kivilinna 		if (nbytes < bsize)
262937c30d7SJussi Kivilinna 			goto done;
263937c30d7SJussi Kivilinna 	}
264937c30d7SJussi Kivilinna 
265937c30d7SJussi Kivilinna 	/* Handle leftovers */
266937c30d7SJussi Kivilinna 	for (;;) {
267937c30d7SJussi Kivilinna 		__serpent_decrypt(ctx, (u8 *)dst, (u8 *)src);
268937c30d7SJussi Kivilinna 
269937c30d7SJussi Kivilinna 		nbytes -= bsize;
270937c30d7SJussi Kivilinna 		if (nbytes < bsize)
271937c30d7SJussi Kivilinna 			break;
272937c30d7SJussi Kivilinna 
273937c30d7SJussi Kivilinna 		u128_xor(dst, dst, src - 1);
274937c30d7SJussi Kivilinna 		src -= 1;
275937c30d7SJussi Kivilinna 		dst -= 1;
276937c30d7SJussi Kivilinna 	}
277937c30d7SJussi Kivilinna 
278937c30d7SJussi Kivilinna done:
279937c30d7SJussi Kivilinna 	u128_xor(dst, dst, (u128 *)walk->iv);
280937c30d7SJussi Kivilinna 	*(u128 *)walk->iv = last_iv;
281937c30d7SJussi Kivilinna 
282937c30d7SJussi Kivilinna 	return nbytes;
283937c30d7SJussi Kivilinna }
284937c30d7SJussi Kivilinna 
285937c30d7SJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
286937c30d7SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
287937c30d7SJussi Kivilinna {
288937c30d7SJussi Kivilinna 	bool fpu_enabled = false;
289937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
290937c30d7SJussi Kivilinna 	int err;
291937c30d7SJussi Kivilinna 
292937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
293937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt(desc, &walk);
294937c30d7SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
295937c30d7SJussi Kivilinna 
296937c30d7SJussi Kivilinna 	while ((nbytes = walk.nbytes)) {
297937c30d7SJussi Kivilinna 		fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
298937c30d7SJussi Kivilinna 		nbytes = __cbc_decrypt(desc, &walk);
299937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
300937c30d7SJussi Kivilinna 	}
301937c30d7SJussi Kivilinna 
302937c30d7SJussi Kivilinna 	serpent_fpu_end(fpu_enabled);
303937c30d7SJussi Kivilinna 	return err;
304937c30d7SJussi Kivilinna }
305937c30d7SJussi Kivilinna 
306937c30d7SJussi Kivilinna static struct crypto_alg blk_cbc_alg = {
307937c30d7SJussi Kivilinna 	.cra_name		= "__cbc-serpent-sse2",
308937c30d7SJussi Kivilinna 	.cra_driver_name	= "__driver-cbc-serpent-sse2",
309937c30d7SJussi Kivilinna 	.cra_priority		= 0,
310937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
311937c30d7SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
312937c30d7SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_ctx),
313937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
314937c30d7SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
315937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
316937c30d7SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(blk_cbc_alg.cra_list),
317937c30d7SJussi Kivilinna 	.cra_u = {
318937c30d7SJussi Kivilinna 		.blkcipher = {
319937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
320937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
321937c30d7SJussi Kivilinna 			.setkey		= serpent_setkey,
322937c30d7SJussi Kivilinna 			.encrypt	= cbc_encrypt,
323937c30d7SJussi Kivilinna 			.decrypt	= cbc_decrypt,
324937c30d7SJussi Kivilinna 		},
325937c30d7SJussi Kivilinna 	},
326937c30d7SJussi Kivilinna };
327937c30d7SJussi Kivilinna 
328937c30d7SJussi Kivilinna static inline void u128_to_be128(be128 *dst, const u128 *src)
329937c30d7SJussi Kivilinna {
330937c30d7SJussi Kivilinna 	dst->a = cpu_to_be64(src->a);
331937c30d7SJussi Kivilinna 	dst->b = cpu_to_be64(src->b);
332937c30d7SJussi Kivilinna }
333937c30d7SJussi Kivilinna 
334937c30d7SJussi Kivilinna static inline void be128_to_u128(u128 *dst, const be128 *src)
335937c30d7SJussi Kivilinna {
336937c30d7SJussi Kivilinna 	dst->a = be64_to_cpu(src->a);
337937c30d7SJussi Kivilinna 	dst->b = be64_to_cpu(src->b);
338937c30d7SJussi Kivilinna }
339937c30d7SJussi Kivilinna 
340937c30d7SJussi Kivilinna static inline void u128_inc(u128 *i)
341937c30d7SJussi Kivilinna {
342937c30d7SJussi Kivilinna 	i->b++;
343937c30d7SJussi Kivilinna 	if (!i->b)
344937c30d7SJussi Kivilinna 		i->a++;
345937c30d7SJussi Kivilinna }
346937c30d7SJussi Kivilinna 
347937c30d7SJussi Kivilinna static void ctr_crypt_final(struct blkcipher_desc *desc,
348937c30d7SJussi Kivilinna 			    struct blkcipher_walk *walk)
349937c30d7SJussi Kivilinna {
350937c30d7SJussi Kivilinna 	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
351937c30d7SJussi Kivilinna 	u8 *ctrblk = walk->iv;
352937c30d7SJussi Kivilinna 	u8 keystream[SERPENT_BLOCK_SIZE];
353937c30d7SJussi Kivilinna 	u8 *src = walk->src.virt.addr;
354937c30d7SJussi Kivilinna 	u8 *dst = walk->dst.virt.addr;
355937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
356937c30d7SJussi Kivilinna 
357937c30d7SJussi Kivilinna 	__serpent_encrypt(ctx, keystream, ctrblk);
358937c30d7SJussi Kivilinna 	crypto_xor(keystream, src, nbytes);
359937c30d7SJussi Kivilinna 	memcpy(dst, keystream, nbytes);
360937c30d7SJussi Kivilinna 
361937c30d7SJussi Kivilinna 	crypto_inc(ctrblk, SERPENT_BLOCK_SIZE);
362937c30d7SJussi Kivilinna }
363937c30d7SJussi Kivilinna 
364937c30d7SJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
365937c30d7SJussi Kivilinna 				struct blkcipher_walk *walk)
366937c30d7SJussi Kivilinna {
367937c30d7SJussi Kivilinna 	struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
368937c30d7SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
369937c30d7SJussi Kivilinna 	unsigned int nbytes = walk->nbytes;
370937c30d7SJussi Kivilinna 	u128 *src = (u128 *)walk->src.virt.addr;
371937c30d7SJussi Kivilinna 	u128 *dst = (u128 *)walk->dst.virt.addr;
372937c30d7SJussi Kivilinna 	u128 ctrblk;
373937c30d7SJussi Kivilinna 	be128 ctrblocks[SERPENT_PARALLEL_BLOCKS];
374937c30d7SJussi Kivilinna 	int i;
375937c30d7SJussi Kivilinna 
376937c30d7SJussi Kivilinna 	be128_to_u128(&ctrblk, (be128 *)walk->iv);
377937c30d7SJussi Kivilinna 
378937c30d7SJussi Kivilinna 	/* Process multi-block batch */
379937c30d7SJussi Kivilinna 	if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
380937c30d7SJussi Kivilinna 		do {
381937c30d7SJussi Kivilinna 			/* create ctrblks for parallel encrypt */
382937c30d7SJussi Kivilinna 			for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
383937c30d7SJussi Kivilinna 				if (dst != src)
384937c30d7SJussi Kivilinna 					dst[i] = src[i];
385937c30d7SJussi Kivilinna 
386937c30d7SJussi Kivilinna 				u128_to_be128(&ctrblocks[i], &ctrblk);
387937c30d7SJussi Kivilinna 				u128_inc(&ctrblk);
388937c30d7SJussi Kivilinna 			}
389937c30d7SJussi Kivilinna 
390937c30d7SJussi Kivilinna 			serpent_enc_blk_xway_xor(ctx, (u8 *)dst,
391937c30d7SJussi Kivilinna 						 (u8 *)ctrblocks);
392937c30d7SJussi Kivilinna 
393937c30d7SJussi Kivilinna 			src += SERPENT_PARALLEL_BLOCKS;
394937c30d7SJussi Kivilinna 			dst += SERPENT_PARALLEL_BLOCKS;
395937c30d7SJussi Kivilinna 			nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
396937c30d7SJussi Kivilinna 		} while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
397937c30d7SJussi Kivilinna 
398937c30d7SJussi Kivilinna 		if (nbytes < bsize)
399937c30d7SJussi Kivilinna 			goto done;
400937c30d7SJussi Kivilinna 	}
401937c30d7SJussi Kivilinna 
402937c30d7SJussi Kivilinna 	/* Handle leftovers */
403937c30d7SJussi Kivilinna 	do {
404937c30d7SJussi Kivilinna 		if (dst != src)
405937c30d7SJussi Kivilinna 			*dst = *src;
406937c30d7SJussi Kivilinna 
407937c30d7SJussi Kivilinna 		u128_to_be128(&ctrblocks[0], &ctrblk);
408937c30d7SJussi Kivilinna 		u128_inc(&ctrblk);
409937c30d7SJussi Kivilinna 
410937c30d7SJussi Kivilinna 		__serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
411937c30d7SJussi Kivilinna 		u128_xor(dst, dst, (u128 *)ctrblocks);
412937c30d7SJussi Kivilinna 
413937c30d7SJussi Kivilinna 		src += 1;
414937c30d7SJussi Kivilinna 		dst += 1;
415937c30d7SJussi Kivilinna 		nbytes -= bsize;
416937c30d7SJussi Kivilinna 	} while (nbytes >= bsize);
417937c30d7SJussi Kivilinna 
418937c30d7SJussi Kivilinna done:
419937c30d7SJussi Kivilinna 	u128_to_be128((be128 *)walk->iv, &ctrblk);
420937c30d7SJussi Kivilinna 	return nbytes;
421937c30d7SJussi Kivilinna }
422937c30d7SJussi Kivilinna 
423937c30d7SJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
424937c30d7SJussi Kivilinna 		     struct scatterlist *src, unsigned int nbytes)
425937c30d7SJussi Kivilinna {
426937c30d7SJussi Kivilinna 	bool fpu_enabled = false;
427937c30d7SJussi Kivilinna 	struct blkcipher_walk walk;
428937c30d7SJussi Kivilinna 	int err;
429937c30d7SJussi Kivilinna 
430937c30d7SJussi Kivilinna 	blkcipher_walk_init(&walk, dst, src, nbytes);
431937c30d7SJussi Kivilinna 	err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE);
432937c30d7SJussi Kivilinna 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
433937c30d7SJussi Kivilinna 
434937c30d7SJussi Kivilinna 	while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) {
435937c30d7SJussi Kivilinna 		fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
436937c30d7SJussi Kivilinna 		nbytes = __ctr_crypt(desc, &walk);
437937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, nbytes);
438937c30d7SJussi Kivilinna 	}
439937c30d7SJussi Kivilinna 
440937c30d7SJussi Kivilinna 	serpent_fpu_end(fpu_enabled);
441937c30d7SJussi Kivilinna 
442937c30d7SJussi Kivilinna 	if (walk.nbytes) {
443937c30d7SJussi Kivilinna 		ctr_crypt_final(desc, &walk);
444937c30d7SJussi Kivilinna 		err = blkcipher_walk_done(desc, &walk, 0);
445937c30d7SJussi Kivilinna 	}
446937c30d7SJussi Kivilinna 
447937c30d7SJussi Kivilinna 	return err;
448937c30d7SJussi Kivilinna }
449937c30d7SJussi Kivilinna 
450937c30d7SJussi Kivilinna static struct crypto_alg blk_ctr_alg = {
451937c30d7SJussi Kivilinna 	.cra_name		= "__ctr-serpent-sse2",
452937c30d7SJussi Kivilinna 	.cra_driver_name	= "__driver-ctr-serpent-sse2",
453937c30d7SJussi Kivilinna 	.cra_priority		= 0,
454937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
455937c30d7SJussi Kivilinna 	.cra_blocksize		= 1,
456937c30d7SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_ctx),
457937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
458937c30d7SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
459937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
460937c30d7SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(blk_ctr_alg.cra_list),
461937c30d7SJussi Kivilinna 	.cra_u = {
462937c30d7SJussi Kivilinna 		.blkcipher = {
463937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
464937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
465937c30d7SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
466937c30d7SJussi Kivilinna 			.setkey		= serpent_setkey,
467937c30d7SJussi Kivilinna 			.encrypt	= ctr_crypt,
468937c30d7SJussi Kivilinna 			.decrypt	= ctr_crypt,
469937c30d7SJussi Kivilinna 		},
470937c30d7SJussi Kivilinna 	},
471937c30d7SJussi Kivilinna };
472937c30d7SJussi Kivilinna 
4735962f8b6SJussi Kivilinna #if defined(HAS_LRW) || defined(HAS_XTS)
47418482053SJussi Kivilinna 
47518482053SJussi Kivilinna struct crypt_priv {
47618482053SJussi Kivilinna 	struct serpent_ctx *ctx;
47718482053SJussi Kivilinna 	bool fpu_enabled;
47818482053SJussi Kivilinna };
47918482053SJussi Kivilinna 
48018482053SJussi Kivilinna static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
48118482053SJussi Kivilinna {
48218482053SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
48318482053SJussi Kivilinna 	struct crypt_priv *ctx = priv;
48418482053SJussi Kivilinna 	int i;
48518482053SJussi Kivilinna 
48618482053SJussi Kivilinna 	ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
48718482053SJussi Kivilinna 
48818482053SJussi Kivilinna 	if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
48918482053SJussi Kivilinna 		serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst);
49018482053SJussi Kivilinna 		return;
49118482053SJussi Kivilinna 	}
49218482053SJussi Kivilinna 
49318482053SJussi Kivilinna 	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
49418482053SJussi Kivilinna 		__serpent_encrypt(ctx->ctx, srcdst, srcdst);
49518482053SJussi Kivilinna }
49618482053SJussi Kivilinna 
49718482053SJussi Kivilinna static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
49818482053SJussi Kivilinna {
49918482053SJussi Kivilinna 	const unsigned int bsize = SERPENT_BLOCK_SIZE;
50018482053SJussi Kivilinna 	struct crypt_priv *ctx = priv;
50118482053SJussi Kivilinna 	int i;
50218482053SJussi Kivilinna 
50318482053SJussi Kivilinna 	ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
50418482053SJussi Kivilinna 
50518482053SJussi Kivilinna 	if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
50618482053SJussi Kivilinna 		serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst);
50718482053SJussi Kivilinna 		return;
50818482053SJussi Kivilinna 	}
50918482053SJussi Kivilinna 
51018482053SJussi Kivilinna 	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
51118482053SJussi Kivilinna 		__serpent_decrypt(ctx->ctx, srcdst, srcdst);
51218482053SJussi Kivilinna }
51318482053SJussi Kivilinna 
5145962f8b6SJussi Kivilinna #endif
5155962f8b6SJussi Kivilinna 
5165962f8b6SJussi Kivilinna #ifdef HAS_LRW
5175962f8b6SJussi Kivilinna 
51818482053SJussi Kivilinna struct serpent_lrw_ctx {
51918482053SJussi Kivilinna 	struct lrw_table_ctx lrw_table;
52018482053SJussi Kivilinna 	struct serpent_ctx serpent_ctx;
52118482053SJussi Kivilinna };
52218482053SJussi Kivilinna 
52318482053SJussi Kivilinna static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
52418482053SJussi Kivilinna 			      unsigned int keylen)
52518482053SJussi Kivilinna {
52618482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
52718482053SJussi Kivilinna 	int err;
52818482053SJussi Kivilinna 
52918482053SJussi Kivilinna 	err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
53018482053SJussi Kivilinna 							SERPENT_BLOCK_SIZE);
53118482053SJussi Kivilinna 	if (err)
53218482053SJussi Kivilinna 		return err;
53318482053SJussi Kivilinna 
53418482053SJussi Kivilinna 	return lrw_init_table(&ctx->lrw_table, key + keylen -
53518482053SJussi Kivilinna 						SERPENT_BLOCK_SIZE);
53618482053SJussi Kivilinna }
53718482053SJussi Kivilinna 
53818482053SJussi Kivilinna static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
53918482053SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
54018482053SJussi Kivilinna {
54118482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
54218482053SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
54318482053SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
54418482053SJussi Kivilinna 		.ctx = &ctx->serpent_ctx,
54518482053SJussi Kivilinna 		.fpu_enabled = false,
54618482053SJussi Kivilinna 	};
54718482053SJussi Kivilinna 	struct lrw_crypt_req req = {
54818482053SJussi Kivilinna 		.tbuf = buf,
54918482053SJussi Kivilinna 		.tbuflen = sizeof(buf),
55018482053SJussi Kivilinna 
55118482053SJussi Kivilinna 		.table_ctx = &ctx->lrw_table,
55218482053SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
55318482053SJussi Kivilinna 		.crypt_fn = encrypt_callback,
55418482053SJussi Kivilinna 	};
55518482053SJussi Kivilinna 	int ret;
55618482053SJussi Kivilinna 
55718482053SJussi Kivilinna 	ret = lrw_crypt(desc, dst, src, nbytes, &req);
55818482053SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
55918482053SJussi Kivilinna 
56018482053SJussi Kivilinna 	return ret;
56118482053SJussi Kivilinna }
56218482053SJussi Kivilinna 
56318482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
56418482053SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
56518482053SJussi Kivilinna {
56618482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
56718482053SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
56818482053SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
56918482053SJussi Kivilinna 		.ctx = &ctx->serpent_ctx,
57018482053SJussi Kivilinna 		.fpu_enabled = false,
57118482053SJussi Kivilinna 	};
57218482053SJussi Kivilinna 	struct lrw_crypt_req req = {
57318482053SJussi Kivilinna 		.tbuf = buf,
57418482053SJussi Kivilinna 		.tbuflen = sizeof(buf),
57518482053SJussi Kivilinna 
57618482053SJussi Kivilinna 		.table_ctx = &ctx->lrw_table,
57718482053SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
57818482053SJussi Kivilinna 		.crypt_fn = decrypt_callback,
57918482053SJussi Kivilinna 	};
58018482053SJussi Kivilinna 	int ret;
58118482053SJussi Kivilinna 
58218482053SJussi Kivilinna 	ret = lrw_crypt(desc, dst, src, nbytes, &req);
58318482053SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
58418482053SJussi Kivilinna 
58518482053SJussi Kivilinna 	return ret;
58618482053SJussi Kivilinna }
58718482053SJussi Kivilinna 
58818482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm)
58918482053SJussi Kivilinna {
59018482053SJussi Kivilinna 	struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
59118482053SJussi Kivilinna 
59218482053SJussi Kivilinna 	lrw_free_table(&ctx->lrw_table);
59318482053SJussi Kivilinna }
59418482053SJussi Kivilinna 
59518482053SJussi Kivilinna static struct crypto_alg blk_lrw_alg = {
59618482053SJussi Kivilinna 	.cra_name		= "__lrw-serpent-sse2",
59718482053SJussi Kivilinna 	.cra_driver_name	= "__driver-lrw-serpent-sse2",
59818482053SJussi Kivilinna 	.cra_priority		= 0,
59918482053SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
60018482053SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
60118482053SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_lrw_ctx),
60218482053SJussi Kivilinna 	.cra_alignmask		= 0,
60318482053SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
60418482053SJussi Kivilinna 	.cra_module		= THIS_MODULE,
60518482053SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(blk_lrw_alg.cra_list),
60618482053SJussi Kivilinna 	.cra_exit		= lrw_exit_tfm,
60718482053SJussi Kivilinna 	.cra_u = {
60818482053SJussi Kivilinna 		.blkcipher = {
60918482053SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE +
61018482053SJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
61118482053SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE +
61218482053SJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
61318482053SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
61418482053SJussi Kivilinna 			.setkey		= lrw_serpent_setkey,
61518482053SJussi Kivilinna 			.encrypt	= lrw_encrypt,
61618482053SJussi Kivilinna 			.decrypt	= lrw_decrypt,
61718482053SJussi Kivilinna 		},
61818482053SJussi Kivilinna 	},
61918482053SJussi Kivilinna };
62018482053SJussi Kivilinna 
62118482053SJussi Kivilinna #endif
62218482053SJussi Kivilinna 
6235962f8b6SJussi Kivilinna #ifdef HAS_XTS
6245962f8b6SJussi Kivilinna 
6255962f8b6SJussi Kivilinna struct serpent_xts_ctx {
6265962f8b6SJussi Kivilinna 	struct serpent_ctx tweak_ctx;
6275962f8b6SJussi Kivilinna 	struct serpent_ctx crypt_ctx;
6285962f8b6SJussi Kivilinna };
6295962f8b6SJussi Kivilinna 
6305962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
6315962f8b6SJussi Kivilinna 			      unsigned int keylen)
6325962f8b6SJussi Kivilinna {
6335962f8b6SJussi Kivilinna 	struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
6345962f8b6SJussi Kivilinna 	u32 *flags = &tfm->crt_flags;
6355962f8b6SJussi Kivilinna 	int err;
6365962f8b6SJussi Kivilinna 
6375962f8b6SJussi Kivilinna 	/* key consists of keys of equal size concatenated, therefore
6385962f8b6SJussi Kivilinna 	 * the length must be even
6395962f8b6SJussi Kivilinna 	 */
6405962f8b6SJussi Kivilinna 	if (keylen % 2) {
6415962f8b6SJussi Kivilinna 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
6425962f8b6SJussi Kivilinna 		return -EINVAL;
6435962f8b6SJussi Kivilinna 	}
6445962f8b6SJussi Kivilinna 
6455962f8b6SJussi Kivilinna 	/* first half of xts-key is for crypt */
6465962f8b6SJussi Kivilinna 	err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
6475962f8b6SJussi Kivilinna 	if (err)
6485962f8b6SJussi Kivilinna 		return err;
6495962f8b6SJussi Kivilinna 
6505962f8b6SJussi Kivilinna 	/* second half of xts-key is for tweak */
6515962f8b6SJussi Kivilinna 	return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
6525962f8b6SJussi Kivilinna }
6535962f8b6SJussi Kivilinna 
6545962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
6555962f8b6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
6565962f8b6SJussi Kivilinna {
6575962f8b6SJussi Kivilinna 	struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
6585962f8b6SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
6595962f8b6SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
6605962f8b6SJussi Kivilinna 		.ctx = &ctx->crypt_ctx,
6615962f8b6SJussi Kivilinna 		.fpu_enabled = false,
6625962f8b6SJussi Kivilinna 	};
6635962f8b6SJussi Kivilinna 	struct xts_crypt_req req = {
6645962f8b6SJussi Kivilinna 		.tbuf = buf,
6655962f8b6SJussi Kivilinna 		.tbuflen = sizeof(buf),
6665962f8b6SJussi Kivilinna 
6675962f8b6SJussi Kivilinna 		.tweak_ctx = &ctx->tweak_ctx,
6685962f8b6SJussi Kivilinna 		.tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
6695962f8b6SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
6705962f8b6SJussi Kivilinna 		.crypt_fn = encrypt_callback,
6715962f8b6SJussi Kivilinna 	};
6725962f8b6SJussi Kivilinna 	int ret;
6735962f8b6SJussi Kivilinna 
6745962f8b6SJussi Kivilinna 	ret = xts_crypt(desc, dst, src, nbytes, &req);
6755962f8b6SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
6765962f8b6SJussi Kivilinna 
6775962f8b6SJussi Kivilinna 	return ret;
6785962f8b6SJussi Kivilinna }
6795962f8b6SJussi Kivilinna 
6805962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
6815962f8b6SJussi Kivilinna 		       struct scatterlist *src, unsigned int nbytes)
6825962f8b6SJussi Kivilinna {
6835962f8b6SJussi Kivilinna 	struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
6845962f8b6SJussi Kivilinna 	be128 buf[SERPENT_PARALLEL_BLOCKS];
6855962f8b6SJussi Kivilinna 	struct crypt_priv crypt_ctx = {
6865962f8b6SJussi Kivilinna 		.ctx = &ctx->crypt_ctx,
6875962f8b6SJussi Kivilinna 		.fpu_enabled = false,
6885962f8b6SJussi Kivilinna 	};
6895962f8b6SJussi Kivilinna 	struct xts_crypt_req req = {
6905962f8b6SJussi Kivilinna 		.tbuf = buf,
6915962f8b6SJussi Kivilinna 		.tbuflen = sizeof(buf),
6925962f8b6SJussi Kivilinna 
6935962f8b6SJussi Kivilinna 		.tweak_ctx = &ctx->tweak_ctx,
6945962f8b6SJussi Kivilinna 		.tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
6955962f8b6SJussi Kivilinna 		.crypt_ctx = &crypt_ctx,
6965962f8b6SJussi Kivilinna 		.crypt_fn = decrypt_callback,
6975962f8b6SJussi Kivilinna 	};
6985962f8b6SJussi Kivilinna 	int ret;
6995962f8b6SJussi Kivilinna 
7005962f8b6SJussi Kivilinna 	ret = xts_crypt(desc, dst, src, nbytes, &req);
7015962f8b6SJussi Kivilinna 	serpent_fpu_end(crypt_ctx.fpu_enabled);
7025962f8b6SJussi Kivilinna 
7035962f8b6SJussi Kivilinna 	return ret;
7045962f8b6SJussi Kivilinna }
7055962f8b6SJussi Kivilinna 
7065962f8b6SJussi Kivilinna static struct crypto_alg blk_xts_alg = {
7075962f8b6SJussi Kivilinna 	.cra_name		= "__xts-serpent-sse2",
7085962f8b6SJussi Kivilinna 	.cra_driver_name	= "__driver-xts-serpent-sse2",
7095962f8b6SJussi Kivilinna 	.cra_priority		= 0,
7105962f8b6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
7115962f8b6SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
7125962f8b6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct serpent_xts_ctx),
7135962f8b6SJussi Kivilinna 	.cra_alignmask		= 0,
7145962f8b6SJussi Kivilinna 	.cra_type		= &crypto_blkcipher_type,
7155962f8b6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
7165962f8b6SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(blk_xts_alg.cra_list),
7175962f8b6SJussi Kivilinna 	.cra_u = {
7185962f8b6SJussi Kivilinna 		.blkcipher = {
7195962f8b6SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
7205962f8b6SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE * 2,
7215962f8b6SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
7225962f8b6SJussi Kivilinna 			.setkey		= xts_serpent_setkey,
7235962f8b6SJussi Kivilinna 			.encrypt	= xts_encrypt,
7245962f8b6SJussi Kivilinna 			.decrypt	= xts_decrypt,
7255962f8b6SJussi Kivilinna 		},
7265962f8b6SJussi Kivilinna 	},
7275962f8b6SJussi Kivilinna };
7285962f8b6SJussi Kivilinna 
7295962f8b6SJussi Kivilinna #endif
7305962f8b6SJussi Kivilinna 
731937c30d7SJussi Kivilinna static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
732937c30d7SJussi Kivilinna 			unsigned int key_len)
733937c30d7SJussi Kivilinna {
734937c30d7SJussi Kivilinna 	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
735937c30d7SJussi Kivilinna 	struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
736937c30d7SJussi Kivilinna 	int err;
737937c30d7SJussi Kivilinna 
738937c30d7SJussi Kivilinna 	crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
739937c30d7SJussi Kivilinna 	crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
740937c30d7SJussi Kivilinna 				    & CRYPTO_TFM_REQ_MASK);
741937c30d7SJussi Kivilinna 	err = crypto_ablkcipher_setkey(child, key, key_len);
742937c30d7SJussi Kivilinna 	crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
743937c30d7SJussi Kivilinna 				    & CRYPTO_TFM_RES_MASK);
744937c30d7SJussi Kivilinna 	return err;
745937c30d7SJussi Kivilinna }
746937c30d7SJussi Kivilinna 
747937c30d7SJussi Kivilinna static int __ablk_encrypt(struct ablkcipher_request *req)
748937c30d7SJussi Kivilinna {
749937c30d7SJussi Kivilinna 	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
750937c30d7SJussi Kivilinna 	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
751937c30d7SJussi Kivilinna 	struct blkcipher_desc desc;
752937c30d7SJussi Kivilinna 
753937c30d7SJussi Kivilinna 	desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
754937c30d7SJussi Kivilinna 	desc.info = req->info;
755937c30d7SJussi Kivilinna 	desc.flags = 0;
756937c30d7SJussi Kivilinna 
757937c30d7SJussi Kivilinna 	return crypto_blkcipher_crt(desc.tfm)->encrypt(
758937c30d7SJussi Kivilinna 		&desc, req->dst, req->src, req->nbytes);
759937c30d7SJussi Kivilinna }
760937c30d7SJussi Kivilinna 
761937c30d7SJussi Kivilinna static int ablk_encrypt(struct ablkcipher_request *req)
762937c30d7SJussi Kivilinna {
763937c30d7SJussi Kivilinna 	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
764937c30d7SJussi Kivilinna 	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
765937c30d7SJussi Kivilinna 
766937c30d7SJussi Kivilinna 	if (!irq_fpu_usable()) {
767937c30d7SJussi Kivilinna 		struct ablkcipher_request *cryptd_req =
768937c30d7SJussi Kivilinna 			ablkcipher_request_ctx(req);
769937c30d7SJussi Kivilinna 
770937c30d7SJussi Kivilinna 		memcpy(cryptd_req, req, sizeof(*req));
771937c30d7SJussi Kivilinna 		ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
772937c30d7SJussi Kivilinna 
773937c30d7SJussi Kivilinna 		return crypto_ablkcipher_encrypt(cryptd_req);
774937c30d7SJussi Kivilinna 	} else {
775937c30d7SJussi Kivilinna 		return __ablk_encrypt(req);
776937c30d7SJussi Kivilinna 	}
777937c30d7SJussi Kivilinna }
778937c30d7SJussi Kivilinna 
779937c30d7SJussi Kivilinna static int ablk_decrypt(struct ablkcipher_request *req)
780937c30d7SJussi Kivilinna {
781937c30d7SJussi Kivilinna 	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
782937c30d7SJussi Kivilinna 	struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
783937c30d7SJussi Kivilinna 
784937c30d7SJussi Kivilinna 	if (!irq_fpu_usable()) {
785937c30d7SJussi Kivilinna 		struct ablkcipher_request *cryptd_req =
786937c30d7SJussi Kivilinna 			ablkcipher_request_ctx(req);
787937c30d7SJussi Kivilinna 
788937c30d7SJussi Kivilinna 		memcpy(cryptd_req, req, sizeof(*req));
789937c30d7SJussi Kivilinna 		ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
790937c30d7SJussi Kivilinna 
791937c30d7SJussi Kivilinna 		return crypto_ablkcipher_decrypt(cryptd_req);
792937c30d7SJussi Kivilinna 	} else {
793937c30d7SJussi Kivilinna 		struct blkcipher_desc desc;
794937c30d7SJussi Kivilinna 
795937c30d7SJussi Kivilinna 		desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
796937c30d7SJussi Kivilinna 		desc.info = req->info;
797937c30d7SJussi Kivilinna 		desc.flags = 0;
798937c30d7SJussi Kivilinna 
799937c30d7SJussi Kivilinna 		return crypto_blkcipher_crt(desc.tfm)->decrypt(
800937c30d7SJussi Kivilinna 			&desc, req->dst, req->src, req->nbytes);
801937c30d7SJussi Kivilinna 	}
802937c30d7SJussi Kivilinna }
803937c30d7SJussi Kivilinna 
804937c30d7SJussi Kivilinna static void ablk_exit(struct crypto_tfm *tfm)
805937c30d7SJussi Kivilinna {
806937c30d7SJussi Kivilinna 	struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
807937c30d7SJussi Kivilinna 
808937c30d7SJussi Kivilinna 	cryptd_free_ablkcipher(ctx->cryptd_tfm);
809937c30d7SJussi Kivilinna }
810937c30d7SJussi Kivilinna 
811937c30d7SJussi Kivilinna static void ablk_init_common(struct crypto_tfm *tfm,
812937c30d7SJussi Kivilinna 			     struct cryptd_ablkcipher *cryptd_tfm)
813937c30d7SJussi Kivilinna {
814937c30d7SJussi Kivilinna 	struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
815937c30d7SJussi Kivilinna 
816937c30d7SJussi Kivilinna 	ctx->cryptd_tfm = cryptd_tfm;
817937c30d7SJussi Kivilinna 	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
818937c30d7SJussi Kivilinna 		crypto_ablkcipher_reqsize(&cryptd_tfm->base);
819937c30d7SJussi Kivilinna }
820937c30d7SJussi Kivilinna 
821937c30d7SJussi Kivilinna static int ablk_ecb_init(struct crypto_tfm *tfm)
822937c30d7SJussi Kivilinna {
823937c30d7SJussi Kivilinna 	struct cryptd_ablkcipher *cryptd_tfm;
824937c30d7SJussi Kivilinna 
825937c30d7SJussi Kivilinna 	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0);
826937c30d7SJussi Kivilinna 	if (IS_ERR(cryptd_tfm))
827937c30d7SJussi Kivilinna 		return PTR_ERR(cryptd_tfm);
828937c30d7SJussi Kivilinna 	ablk_init_common(tfm, cryptd_tfm);
829937c30d7SJussi Kivilinna 	return 0;
830937c30d7SJussi Kivilinna }
831937c30d7SJussi Kivilinna 
832937c30d7SJussi Kivilinna static struct crypto_alg ablk_ecb_alg = {
833937c30d7SJussi Kivilinna 	.cra_name		= "ecb(serpent)",
834937c30d7SJussi Kivilinna 	.cra_driver_name	= "ecb-serpent-sse2",
835937c30d7SJussi Kivilinna 	.cra_priority		= 400,
836937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
837937c30d7SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
838937c30d7SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
839937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
840937c30d7SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
841937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
842937c30d7SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
843937c30d7SJussi Kivilinna 	.cra_init		= ablk_ecb_init,
844937c30d7SJussi Kivilinna 	.cra_exit		= ablk_exit,
845937c30d7SJussi Kivilinna 	.cra_u = {
846937c30d7SJussi Kivilinna 		.ablkcipher = {
847937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
848937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
849937c30d7SJussi Kivilinna 			.setkey		= ablk_set_key,
850937c30d7SJussi Kivilinna 			.encrypt	= ablk_encrypt,
851937c30d7SJussi Kivilinna 			.decrypt	= ablk_decrypt,
852937c30d7SJussi Kivilinna 		},
853937c30d7SJussi Kivilinna 	},
854937c30d7SJussi Kivilinna };
855937c30d7SJussi Kivilinna 
856937c30d7SJussi Kivilinna static int ablk_cbc_init(struct crypto_tfm *tfm)
857937c30d7SJussi Kivilinna {
858937c30d7SJussi Kivilinna 	struct cryptd_ablkcipher *cryptd_tfm;
859937c30d7SJussi Kivilinna 
860937c30d7SJussi Kivilinna 	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0);
861937c30d7SJussi Kivilinna 	if (IS_ERR(cryptd_tfm))
862937c30d7SJussi Kivilinna 		return PTR_ERR(cryptd_tfm);
863937c30d7SJussi Kivilinna 	ablk_init_common(tfm, cryptd_tfm);
864937c30d7SJussi Kivilinna 	return 0;
865937c30d7SJussi Kivilinna }
866937c30d7SJussi Kivilinna 
867937c30d7SJussi Kivilinna static struct crypto_alg ablk_cbc_alg = {
868937c30d7SJussi Kivilinna 	.cra_name		= "cbc(serpent)",
869937c30d7SJussi Kivilinna 	.cra_driver_name	= "cbc-serpent-sse2",
870937c30d7SJussi Kivilinna 	.cra_priority		= 400,
871937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
872937c30d7SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
873937c30d7SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
874937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
875937c30d7SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
876937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
877937c30d7SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
878937c30d7SJussi Kivilinna 	.cra_init		= ablk_cbc_init,
879937c30d7SJussi Kivilinna 	.cra_exit		= ablk_exit,
880937c30d7SJussi Kivilinna 	.cra_u = {
881937c30d7SJussi Kivilinna 		.ablkcipher = {
882937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
883937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
884937c30d7SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
885937c30d7SJussi Kivilinna 			.setkey		= ablk_set_key,
886937c30d7SJussi Kivilinna 			.encrypt	= __ablk_encrypt,
887937c30d7SJussi Kivilinna 			.decrypt	= ablk_decrypt,
888937c30d7SJussi Kivilinna 		},
889937c30d7SJussi Kivilinna 	},
890937c30d7SJussi Kivilinna };
891937c30d7SJussi Kivilinna 
892937c30d7SJussi Kivilinna static int ablk_ctr_init(struct crypto_tfm *tfm)
893937c30d7SJussi Kivilinna {
894937c30d7SJussi Kivilinna 	struct cryptd_ablkcipher *cryptd_tfm;
895937c30d7SJussi Kivilinna 
896937c30d7SJussi Kivilinna 	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0);
897937c30d7SJussi Kivilinna 	if (IS_ERR(cryptd_tfm))
898937c30d7SJussi Kivilinna 		return PTR_ERR(cryptd_tfm);
899937c30d7SJussi Kivilinna 	ablk_init_common(tfm, cryptd_tfm);
900937c30d7SJussi Kivilinna 	return 0;
901937c30d7SJussi Kivilinna }
902937c30d7SJussi Kivilinna 
903937c30d7SJussi Kivilinna static struct crypto_alg ablk_ctr_alg = {
904937c30d7SJussi Kivilinna 	.cra_name		= "ctr(serpent)",
905937c30d7SJussi Kivilinna 	.cra_driver_name	= "ctr-serpent-sse2",
906937c30d7SJussi Kivilinna 	.cra_priority		= 400,
907937c30d7SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
908937c30d7SJussi Kivilinna 	.cra_blocksize		= 1,
909937c30d7SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
910937c30d7SJussi Kivilinna 	.cra_alignmask		= 0,
911937c30d7SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
912937c30d7SJussi Kivilinna 	.cra_module		= THIS_MODULE,
913937c30d7SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
914937c30d7SJussi Kivilinna 	.cra_init		= ablk_ctr_init,
915937c30d7SJussi Kivilinna 	.cra_exit		= ablk_exit,
916937c30d7SJussi Kivilinna 	.cra_u = {
917937c30d7SJussi Kivilinna 		.ablkcipher = {
918937c30d7SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
919937c30d7SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE,
920937c30d7SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
921937c30d7SJussi Kivilinna 			.setkey		= ablk_set_key,
922937c30d7SJussi Kivilinna 			.encrypt	= ablk_encrypt,
923937c30d7SJussi Kivilinna 			.decrypt	= ablk_encrypt,
924937c30d7SJussi Kivilinna 			.geniv		= "chainiv",
925937c30d7SJussi Kivilinna 		},
926937c30d7SJussi Kivilinna 	},
927937c30d7SJussi Kivilinna };
928937c30d7SJussi Kivilinna 
92918482053SJussi Kivilinna #ifdef HAS_LRW
93018482053SJussi Kivilinna 
93118482053SJussi Kivilinna static int ablk_lrw_init(struct crypto_tfm *tfm)
93218482053SJussi Kivilinna {
93318482053SJussi Kivilinna 	struct cryptd_ablkcipher *cryptd_tfm;
93418482053SJussi Kivilinna 
93518482053SJussi Kivilinna 	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0);
93618482053SJussi Kivilinna 	if (IS_ERR(cryptd_tfm))
93718482053SJussi Kivilinna 		return PTR_ERR(cryptd_tfm);
93818482053SJussi Kivilinna 	ablk_init_common(tfm, cryptd_tfm);
93918482053SJussi Kivilinna 	return 0;
94018482053SJussi Kivilinna }
94118482053SJussi Kivilinna 
94218482053SJussi Kivilinna static struct crypto_alg ablk_lrw_alg = {
94318482053SJussi Kivilinna 	.cra_name		= "lrw(serpent)",
94418482053SJussi Kivilinna 	.cra_driver_name	= "lrw-serpent-sse2",
94518482053SJussi Kivilinna 	.cra_priority		= 400,
94618482053SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
94718482053SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
94818482053SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
94918482053SJussi Kivilinna 	.cra_alignmask		= 0,
95018482053SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
95118482053SJussi Kivilinna 	.cra_module		= THIS_MODULE,
95218482053SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
95318482053SJussi Kivilinna 	.cra_init		= ablk_lrw_init,
95418482053SJussi Kivilinna 	.cra_exit		= ablk_exit,
95518482053SJussi Kivilinna 	.cra_u = {
95618482053SJussi Kivilinna 		.ablkcipher = {
95718482053SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE +
95818482053SJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
95918482053SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE +
96018482053SJussi Kivilinna 					  SERPENT_BLOCK_SIZE,
96118482053SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
96218482053SJussi Kivilinna 			.setkey		= ablk_set_key,
96318482053SJussi Kivilinna 			.encrypt	= ablk_encrypt,
96418482053SJussi Kivilinna 			.decrypt	= ablk_decrypt,
96518482053SJussi Kivilinna 		},
96618482053SJussi Kivilinna 	},
96718482053SJussi Kivilinna };
96818482053SJussi Kivilinna 
96918482053SJussi Kivilinna #endif
97018482053SJussi Kivilinna 
9715962f8b6SJussi Kivilinna #ifdef HAS_XTS
9725962f8b6SJussi Kivilinna 
9735962f8b6SJussi Kivilinna static int ablk_xts_init(struct crypto_tfm *tfm)
9745962f8b6SJussi Kivilinna {
9755962f8b6SJussi Kivilinna 	struct cryptd_ablkcipher *cryptd_tfm;
9765962f8b6SJussi Kivilinna 
9775962f8b6SJussi Kivilinna 	cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0);
9785962f8b6SJussi Kivilinna 	if (IS_ERR(cryptd_tfm))
9795962f8b6SJussi Kivilinna 		return PTR_ERR(cryptd_tfm);
9805962f8b6SJussi Kivilinna 	ablk_init_common(tfm, cryptd_tfm);
9815962f8b6SJussi Kivilinna 	return 0;
9825962f8b6SJussi Kivilinna }
9835962f8b6SJussi Kivilinna 
9845962f8b6SJussi Kivilinna static struct crypto_alg ablk_xts_alg = {
9855962f8b6SJussi Kivilinna 	.cra_name		= "xts(serpent)",
9865962f8b6SJussi Kivilinna 	.cra_driver_name	= "xts-serpent-sse2",
9875962f8b6SJussi Kivilinna 	.cra_priority		= 400,
9885962f8b6SJussi Kivilinna 	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
9895962f8b6SJussi Kivilinna 	.cra_blocksize		= SERPENT_BLOCK_SIZE,
9905962f8b6SJussi Kivilinna 	.cra_ctxsize		= sizeof(struct async_serpent_ctx),
9915962f8b6SJussi Kivilinna 	.cra_alignmask		= 0,
9925962f8b6SJussi Kivilinna 	.cra_type		= &crypto_ablkcipher_type,
9935962f8b6SJussi Kivilinna 	.cra_module		= THIS_MODULE,
9945962f8b6SJussi Kivilinna 	.cra_list		= LIST_HEAD_INIT(ablk_xts_alg.cra_list),
9955962f8b6SJussi Kivilinna 	.cra_init		= ablk_xts_init,
9965962f8b6SJussi Kivilinna 	.cra_exit		= ablk_exit,
9975962f8b6SJussi Kivilinna 	.cra_u = {
9985962f8b6SJussi Kivilinna 		.ablkcipher = {
9995962f8b6SJussi Kivilinna 			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
10005962f8b6SJussi Kivilinna 			.max_keysize	= SERPENT_MAX_KEY_SIZE * 2,
10015962f8b6SJussi Kivilinna 			.ivsize		= SERPENT_BLOCK_SIZE,
10025962f8b6SJussi Kivilinna 			.setkey		= ablk_set_key,
10035962f8b6SJussi Kivilinna 			.encrypt	= ablk_encrypt,
10045962f8b6SJussi Kivilinna 			.decrypt	= ablk_decrypt,
10055962f8b6SJussi Kivilinna 		},
10065962f8b6SJussi Kivilinna 	},
10075962f8b6SJussi Kivilinna };
10085962f8b6SJussi Kivilinna 
10095962f8b6SJussi Kivilinna #endif
10105962f8b6SJussi Kivilinna 
1011937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void)
1012937c30d7SJussi Kivilinna {
1013937c30d7SJussi Kivilinna 	int err;
1014937c30d7SJussi Kivilinna 
1015937c30d7SJussi Kivilinna 	if (!cpu_has_xmm2) {
1016937c30d7SJussi Kivilinna 		printk(KERN_INFO "SSE2 instructions are not detected.\n");
1017937c30d7SJussi Kivilinna 		return -ENODEV;
1018937c30d7SJussi Kivilinna 	}
1019937c30d7SJussi Kivilinna 
1020937c30d7SJussi Kivilinna 	err = crypto_register_alg(&blk_ecb_alg);
1021937c30d7SJussi Kivilinna 	if (err)
1022937c30d7SJussi Kivilinna 		goto blk_ecb_err;
1023937c30d7SJussi Kivilinna 	err = crypto_register_alg(&blk_cbc_alg);
1024937c30d7SJussi Kivilinna 	if (err)
1025937c30d7SJussi Kivilinna 		goto blk_cbc_err;
1026937c30d7SJussi Kivilinna 	err = crypto_register_alg(&blk_ctr_alg);
1027937c30d7SJussi Kivilinna 	if (err)
1028937c30d7SJussi Kivilinna 		goto blk_ctr_err;
1029937c30d7SJussi Kivilinna 	err = crypto_register_alg(&ablk_ecb_alg);
1030937c30d7SJussi Kivilinna 	if (err)
1031937c30d7SJussi Kivilinna 		goto ablk_ecb_err;
1032937c30d7SJussi Kivilinna 	err = crypto_register_alg(&ablk_cbc_alg);
1033937c30d7SJussi Kivilinna 	if (err)
1034937c30d7SJussi Kivilinna 		goto ablk_cbc_err;
1035937c30d7SJussi Kivilinna 	err = crypto_register_alg(&ablk_ctr_alg);
1036937c30d7SJussi Kivilinna 	if (err)
1037937c30d7SJussi Kivilinna 		goto ablk_ctr_err;
103818482053SJussi Kivilinna #ifdef HAS_LRW
103918482053SJussi Kivilinna 	err = crypto_register_alg(&blk_lrw_alg);
104018482053SJussi Kivilinna 	if (err)
104118482053SJussi Kivilinna 		goto blk_lrw_err;
104218482053SJussi Kivilinna 	err = crypto_register_alg(&ablk_lrw_alg);
104318482053SJussi Kivilinna 	if (err)
104418482053SJussi Kivilinna 		goto ablk_lrw_err;
104518482053SJussi Kivilinna #endif
10465962f8b6SJussi Kivilinna #ifdef HAS_XTS
10475962f8b6SJussi Kivilinna 	err = crypto_register_alg(&blk_xts_alg);
10485962f8b6SJussi Kivilinna 	if (err)
10495962f8b6SJussi Kivilinna 		goto blk_xts_err;
10505962f8b6SJussi Kivilinna 	err = crypto_register_alg(&ablk_xts_alg);
10515962f8b6SJussi Kivilinna 	if (err)
10525962f8b6SJussi Kivilinna 		goto ablk_xts_err;
10535962f8b6SJussi Kivilinna #endif
1054937c30d7SJussi Kivilinna 	return err;
1055937c30d7SJussi Kivilinna 
10565962f8b6SJussi Kivilinna #ifdef HAS_XTS
10575962f8b6SJussi Kivilinna 	crypto_unregister_alg(&ablk_xts_alg);
10585962f8b6SJussi Kivilinna ablk_xts_err:
10595962f8b6SJussi Kivilinna 	crypto_unregister_alg(&blk_xts_alg);
10605962f8b6SJussi Kivilinna blk_xts_err:
10615962f8b6SJussi Kivilinna #endif
106218482053SJussi Kivilinna #ifdef HAS_LRW
10635962f8b6SJussi Kivilinna 	crypto_unregister_alg(&ablk_lrw_alg);
106418482053SJussi Kivilinna ablk_lrw_err:
106518482053SJussi Kivilinna 	crypto_unregister_alg(&blk_lrw_alg);
106618482053SJussi Kivilinna blk_lrw_err:
106718482053SJussi Kivilinna #endif
10685962f8b6SJussi Kivilinna 	crypto_unregister_alg(&ablk_ctr_alg);
1069937c30d7SJussi Kivilinna ablk_ctr_err:
1070937c30d7SJussi Kivilinna 	crypto_unregister_alg(&ablk_cbc_alg);
1071937c30d7SJussi Kivilinna ablk_cbc_err:
1072937c30d7SJussi Kivilinna 	crypto_unregister_alg(&ablk_ecb_alg);
1073937c30d7SJussi Kivilinna ablk_ecb_err:
1074937c30d7SJussi Kivilinna 	crypto_unregister_alg(&blk_ctr_alg);
1075937c30d7SJussi Kivilinna blk_ctr_err:
1076937c30d7SJussi Kivilinna 	crypto_unregister_alg(&blk_cbc_alg);
1077937c30d7SJussi Kivilinna blk_cbc_err:
1078937c30d7SJussi Kivilinna 	crypto_unregister_alg(&blk_ecb_alg);
1079937c30d7SJussi Kivilinna blk_ecb_err:
1080937c30d7SJussi Kivilinna 	return err;
1081937c30d7SJussi Kivilinna }
1082937c30d7SJussi Kivilinna 
1083937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void)
1084937c30d7SJussi Kivilinna {
10855962f8b6SJussi Kivilinna #ifdef HAS_XTS
10865962f8b6SJussi Kivilinna 	crypto_unregister_alg(&ablk_xts_alg);
10875962f8b6SJussi Kivilinna 	crypto_unregister_alg(&blk_xts_alg);
10885962f8b6SJussi Kivilinna #endif
108918482053SJussi Kivilinna #ifdef HAS_LRW
109018482053SJussi Kivilinna 	crypto_unregister_alg(&ablk_lrw_alg);
109118482053SJussi Kivilinna 	crypto_unregister_alg(&blk_lrw_alg);
109218482053SJussi Kivilinna #endif
1093937c30d7SJussi Kivilinna 	crypto_unregister_alg(&ablk_ctr_alg);
1094937c30d7SJussi Kivilinna 	crypto_unregister_alg(&ablk_cbc_alg);
1095937c30d7SJussi Kivilinna 	crypto_unregister_alg(&ablk_ecb_alg);
1096937c30d7SJussi Kivilinna 	crypto_unregister_alg(&blk_ctr_alg);
1097937c30d7SJussi Kivilinna 	crypto_unregister_alg(&blk_cbc_alg);
1098937c30d7SJussi Kivilinna 	crypto_unregister_alg(&blk_ecb_alg);
1099937c30d7SJussi Kivilinna }
1100937c30d7SJussi Kivilinna 
1101937c30d7SJussi Kivilinna module_init(serpent_sse2_init);
1102937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit);
1103937c30d7SJussi Kivilinna 
1104937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized");
1105937c30d7SJussi Kivilinna MODULE_LICENSE("GPL");
1106937c30d7SJussi Kivilinna MODULE_ALIAS("serpent");
1107