xref: /linux/drivers/crypto/geode-aes.c (revision 40efcb05f213180b7cc8fd8d963377305f236c28)
1  /* Copyright (C) 2004-2006, Advanced Micro Devices, Inc.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  */
8 
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/pci.h>
12 #include <linux/pci_ids.h>
13 #include <linux/crypto.h>
14 #include <linux/spinlock.h>
15 #include <crypto/algapi.h>
16 
17 #include <asm/io.h>
18 #include <asm/delay.h>
19 
20 #include "geode-aes.h"
21 
22 /* Register definitions */
23 
24 #define AES_CTRLA_REG  0x0000
25 
26 #define AES_CTRL_START     0x01
27 #define AES_CTRL_DECRYPT   0x00
28 #define AES_CTRL_ENCRYPT   0x02
29 #define AES_CTRL_WRKEY     0x04
30 #define AES_CTRL_DCA       0x08
31 #define AES_CTRL_SCA       0x10
32 #define AES_CTRL_CBC       0x20
33 
34 #define AES_INTR_REG  0x0008
35 
36 #define AES_INTRA_PENDING (1 << 16)
37 #define AES_INTRB_PENDING (1 << 17)
38 
39 #define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
40 #define AES_INTR_MASK     0x07
41 
42 #define AES_SOURCEA_REG   0x0010
43 #define AES_DSTA_REG      0x0014
44 #define AES_LENA_REG      0x0018
45 #define AES_WRITEKEY0_REG 0x0030
46 #define AES_WRITEIV0_REG  0x0040
47 
48 /*  A very large counter that is used to gracefully bail out of an
49  *  operation in case of trouble
50  */
51 
52 #define AES_OP_TIMEOUT    0x50000
53 
54 /* Static structures */
55 
56 static void __iomem * _iobase;
57 static spinlock_t lock;
58 
59 /* Write a 128 bit field (either a writable key or IV) */
60 static inline void
61 _writefield(u32 offset, void *value)
62 {
63 	int i;
64 	for(i = 0; i < 4; i++)
65 		iowrite32(((u32 *) value)[i], _iobase + offset + (i * 4));
66 }
67 
68 /* Read a 128 bit field (either a writable key or IV) */
69 static inline void
70 _readfield(u32 offset, void *value)
71 {
72 	int i;
73 	for(i = 0; i < 4; i++)
74 		((u32 *) value)[i] = ioread32(_iobase + offset + (i * 4));
75 }
76 
77 static int
78 do_crypt(void *src, void *dst, int len, u32 flags)
79 {
80 	u32 status;
81 	u32 counter = AES_OP_TIMEOUT;
82 
83 	iowrite32(virt_to_phys(src), _iobase + AES_SOURCEA_REG);
84 	iowrite32(virt_to_phys(dst), _iobase + AES_DSTA_REG);
85 	iowrite32(len,  _iobase + AES_LENA_REG);
86 
87 	/* Start the operation */
88 	iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG);
89 
90 	do
91 		status = ioread32(_iobase + AES_INTR_REG);
92 	while(!(status & AES_INTRA_PENDING) && --counter);
93 
94 	/* Clear the event */
95 	iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG);
96 	return counter ? 0 : 1;
97 }
98 
99 static unsigned int
100 geode_aes_crypt(struct geode_aes_op *op)
101 {
102 	u32 flags = 0;
103 	unsigned long iflags;
104 
105 	if (op->len == 0)
106 		return 0;
107 
108 	/* If the source and destination is the same, then
109 	 * we need to turn on the coherent flags, otherwise
110 	 * we don't need to worry
111 	 */
112 
113 	flags |= (AES_CTRL_DCA | AES_CTRL_SCA);
114 
115 	if (op->dir == AES_DIR_ENCRYPT)
116 		flags |= AES_CTRL_ENCRYPT;
117 
118 	/* Start the critical section */
119 
120 	spin_lock_irqsave(&lock, iflags);
121 
122 	if (op->mode == AES_MODE_CBC) {
123 		flags |= AES_CTRL_CBC;
124 		_writefield(AES_WRITEIV0_REG, op->iv);
125 	}
126 
127 	if (!(op->flags & AES_FLAGS_HIDDENKEY)) {
128 		flags |= AES_CTRL_WRKEY;
129 		_writefield(AES_WRITEKEY0_REG, op->key);
130 	}
131 
132 	do_crypt(op->src, op->dst, op->len, flags);
133 
134 	if (op->mode == AES_MODE_CBC)
135 		_readfield(AES_WRITEIV0_REG, op->iv);
136 
137 	spin_unlock_irqrestore(&lock, iflags);
138 
139 	return op->len;
140 }
141 
142 /* CRYPTO-API Functions */
143 
144 static int
145 geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len)
146 {
147 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
148 
149 	if (len != AES_KEY_LENGTH) {
150 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
151 		return -EINVAL;
152 	}
153 
154 	memcpy(op->key, key, len);
155 	return 0;
156 }
157 
158 static void
159 geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
160 {
161 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
162 
163 	if ((out == NULL) || (in == NULL))
164 		return;
165 
166 	op->src = (void *) in;
167 	op->dst = (void *) out;
168 	op->mode = AES_MODE_ECB;
169 	op->flags = 0;
170 	op->len = AES_MIN_BLOCK_SIZE;
171 	op->dir = AES_DIR_ENCRYPT;
172 
173 	geode_aes_crypt(op);
174 }
175 
176 
177 static void
178 geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
179 {
180 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
181 
182 	if ((out == NULL) || (in == NULL))
183 		return;
184 
185 	op->src = (void *) in;
186 	op->dst = (void *) out;
187 	op->mode = AES_MODE_ECB;
188 	op->flags = 0;
189 	op->len = AES_MIN_BLOCK_SIZE;
190 	op->dir = AES_DIR_DECRYPT;
191 
192 	geode_aes_crypt(op);
193 }
194 
195 
196 static struct crypto_alg geode_alg = {
197 	.cra_name               =       "aes",
198 	.cra_driver_name	=       "geode-aes-128",
199 	.cra_priority           =       300,
200 	.cra_alignmask          =       15,
201 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
202 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
203 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
204 	.cra_module		=	THIS_MODULE,
205 	.cra_list		=	LIST_HEAD_INIT(geode_alg.cra_list),
206 	.cra_u			=	{
207 		.cipher = {
208 			.cia_min_keysize	=  AES_KEY_LENGTH,
209 			.cia_max_keysize	=  AES_KEY_LENGTH,
210 			.cia_setkey		=  geode_setkey,
211 			.cia_encrypt		=  geode_encrypt,
212 			.cia_decrypt		=  geode_decrypt
213 		}
214 	}
215 };
216 
217 static int
218 geode_cbc_decrypt(struct blkcipher_desc *desc,
219 		  struct scatterlist *dst, struct scatterlist *src,
220 		  unsigned int nbytes)
221 {
222 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
223 	struct blkcipher_walk walk;
224 	int err, ret;
225 
226 	blkcipher_walk_init(&walk, dst, src, nbytes);
227 	err = blkcipher_walk_virt(desc, &walk);
228 
229 	while((nbytes = walk.nbytes)) {
230 		op->src = walk.src.virt.addr,
231 		op->dst = walk.dst.virt.addr;
232 		op->mode = AES_MODE_CBC;
233 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
234 		op->dir = AES_DIR_DECRYPT;
235 
236 		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
237 
238 		ret = geode_aes_crypt(op);
239 
240 		memcpy(walk.iv, op->iv, AES_IV_LENGTH);
241 		nbytes -= ret;
242 
243 		err = blkcipher_walk_done(desc, &walk, nbytes);
244 	}
245 
246 	return err;
247 }
248 
249 static int
250 geode_cbc_encrypt(struct blkcipher_desc *desc,
251 		  struct scatterlist *dst, struct scatterlist *src,
252 		  unsigned int nbytes)
253 {
254 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
255 	struct blkcipher_walk walk;
256 	int err, ret;
257 
258 	blkcipher_walk_init(&walk, dst, src, nbytes);
259 	err = blkcipher_walk_virt(desc, &walk);
260 
261 	while((nbytes = walk.nbytes)) {
262 		op->src = walk.src.virt.addr,
263 		op->dst = walk.dst.virt.addr;
264 		op->mode = AES_MODE_CBC;
265 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
266 		op->dir = AES_DIR_ENCRYPT;
267 
268 		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
269 
270 		ret = geode_aes_crypt(op);
271 		nbytes -= ret;
272 		err = blkcipher_walk_done(desc, &walk, nbytes);
273 	}
274 
275 	return err;
276 }
277 
278 static struct crypto_alg geode_cbc_alg = {
279 	.cra_name		=	"cbc(aes)",
280 	.cra_driver_name	=	"cbc-aes-geode-128",
281 	.cra_priority		=	400,
282 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
283 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
284 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
285 	.cra_alignmask		=	15,
286 	.cra_type		=	&crypto_blkcipher_type,
287 	.cra_module		=	THIS_MODULE,
288 	.cra_list		=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
289 	.cra_u			=	{
290 		.blkcipher = {
291 			.min_keysize		=	AES_KEY_LENGTH,
292 			.max_keysize		=	AES_KEY_LENGTH,
293 			.setkey			=	geode_setkey,
294 			.encrypt		=	geode_cbc_encrypt,
295 			.decrypt		=	geode_cbc_decrypt,
296 			.ivsize			=	AES_IV_LENGTH,
297 		}
298 	}
299 };
300 
301 static int
302 geode_ecb_decrypt(struct blkcipher_desc *desc,
303 		  struct scatterlist *dst, struct scatterlist *src,
304 		  unsigned int nbytes)
305 {
306 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
307 	struct blkcipher_walk walk;
308 	int err, ret;
309 
310 	blkcipher_walk_init(&walk, dst, src, nbytes);
311 	err = blkcipher_walk_virt(desc, &walk);
312 
313 	while((nbytes = walk.nbytes)) {
314 		op->src = walk.src.virt.addr,
315 		op->dst = walk.dst.virt.addr;
316 		op->mode = AES_MODE_ECB;
317 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
318 		op->dir = AES_DIR_DECRYPT;
319 
320 		ret = geode_aes_crypt(op);
321 		nbytes -= ret;
322 		err = blkcipher_walk_done(desc, &walk, nbytes);
323 	}
324 
325 	return err;
326 }
327 
328 static int
329 geode_ecb_encrypt(struct blkcipher_desc *desc,
330 		  struct scatterlist *dst, struct scatterlist *src,
331 		  unsigned int nbytes)
332 {
333 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
334 	struct blkcipher_walk walk;
335 	int err, ret;
336 
337 	blkcipher_walk_init(&walk, dst, src, nbytes);
338 	err = blkcipher_walk_virt(desc, &walk);
339 
340 	while((nbytes = walk.nbytes)) {
341 		op->src = walk.src.virt.addr,
342 		op->dst = walk.dst.virt.addr;
343 		op->mode = AES_MODE_ECB;
344 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
345 		op->dir = AES_DIR_ENCRYPT;
346 
347 		ret = geode_aes_crypt(op);
348 		nbytes -= ret;
349 		ret =  blkcipher_walk_done(desc, &walk, nbytes);
350 	}
351 
352 	return err;
353 }
354 
355 static struct crypto_alg geode_ecb_alg = {
356 	.cra_name		=	"ecb(aes)",
357 	.cra_driver_name	=	"ecb-aes-geode-128",
358 	.cra_priority		=	400,
359 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
360 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
361 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
362 	.cra_alignmask		=	15,
363 	.cra_type		=	&crypto_blkcipher_type,
364 	.cra_module		=	THIS_MODULE,
365 	.cra_list		=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
366 	.cra_u			=	{
367 		.blkcipher = {
368 			.min_keysize		=	AES_KEY_LENGTH,
369 			.max_keysize		=	AES_KEY_LENGTH,
370 			.setkey			=	geode_setkey,
371 			.encrypt		=	geode_ecb_encrypt,
372 			.decrypt		=	geode_ecb_decrypt,
373 		}
374 	}
375 };
376 
377 static void
378 geode_aes_remove(struct pci_dev *dev)
379 {
380 	crypto_unregister_alg(&geode_alg);
381 	crypto_unregister_alg(&geode_ecb_alg);
382 	crypto_unregister_alg(&geode_cbc_alg);
383 
384 	pci_iounmap(dev, _iobase);
385 	_iobase = NULL;
386 
387 	pci_release_regions(dev);
388 	pci_disable_device(dev);
389 }
390 
391 
392 static int
393 geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
394 {
395 	int ret;
396 
397 	if ((ret = pci_enable_device(dev)))
398 		return ret;
399 
400 	if ((ret = pci_request_regions(dev, "geode-aes-128")))
401 		goto eenable;
402 
403 	_iobase = pci_iomap(dev, 0, 0);
404 
405 	if (_iobase == NULL) {
406 		ret = -ENOMEM;
407 		goto erequest;
408 	}
409 
410 	spin_lock_init(&lock);
411 
412 	/* Clear any pending activity */
413 	iowrite32(AES_INTR_PENDING | AES_INTR_MASK, _iobase + AES_INTR_REG);
414 
415 	if ((ret = crypto_register_alg(&geode_alg)))
416 		goto eiomap;
417 
418 	if ((ret = crypto_register_alg(&geode_ecb_alg)))
419 		goto ealg;
420 
421 	if ((ret = crypto_register_alg(&geode_cbc_alg)))
422 		goto eecb;
423 
424 	printk(KERN_NOTICE "geode-aes: GEODE AES engine enabled.\n");
425 	return 0;
426 
427  eecb:
428 	crypto_unregister_alg(&geode_ecb_alg);
429 
430  ealg:
431 	crypto_unregister_alg(&geode_alg);
432 
433  eiomap:
434 	pci_iounmap(dev, _iobase);
435 
436  erequest:
437 	pci_release_regions(dev);
438 
439  eenable:
440 	pci_disable_device(dev);
441 
442 	printk(KERN_ERR "geode-aes:  GEODE AES initialization failed.\n");
443 	return ret;
444 }
445 
446 static struct pci_device_id geode_aes_tbl[] = {
447 	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, PCI_ANY_ID, PCI_ANY_ID} ,
448 	{ 0, }
449 };
450 
451 MODULE_DEVICE_TABLE(pci, geode_aes_tbl);
452 
453 static struct pci_driver geode_aes_driver = {
454 	.name = "Geode LX AES",
455 	.id_table = geode_aes_tbl,
456 	.probe = geode_aes_probe,
457 	.remove = __devexit_p(geode_aes_remove)
458 };
459 
460 static int __init
461 geode_aes_init(void)
462 {
463 	return pci_register_driver(&geode_aes_driver);
464 }
465 
466 static void __exit
467 geode_aes_exit(void)
468 {
469 	pci_unregister_driver(&geode_aes_driver);
470 }
471 
472 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
473 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
474 MODULE_LICENSE("GPL");
475 MODULE_ALIAS("aes");
476 
477 module_init(geode_aes_init);
478 module_exit(geode_aes_exit);
479