xref: /linux/drivers/crypto/geode-aes.c (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
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 || op->src == op->dst)
106 		return 0;
107 
108 	if (op->flags & AES_FLAGS_COHERENT)
109 		flags |= (AES_CTRL_DCA | AES_CTRL_SCA);
110 
111 	if (op->dir == AES_DIR_ENCRYPT)
112 		flags |= AES_CTRL_ENCRYPT;
113 
114 	/* Start the critical section */
115 
116 	spin_lock_irqsave(&lock, iflags);
117 
118 	if (op->mode == AES_MODE_CBC) {
119 		flags |= AES_CTRL_CBC;
120 		_writefield(AES_WRITEIV0_REG, op->iv);
121 	}
122 
123 	if (op->flags & AES_FLAGS_USRKEY) {
124 		flags |= AES_CTRL_WRKEY;
125 		_writefield(AES_WRITEKEY0_REG, op->key);
126 	}
127 
128 	do_crypt(op->src, op->dst, op->len, flags);
129 
130 	if (op->mode == AES_MODE_CBC)
131 		_readfield(AES_WRITEIV0_REG, op->iv);
132 
133 	spin_unlock_irqrestore(&lock, iflags);
134 
135 	return op->len;
136 }
137 
138 /* CRYPTO-API Functions */
139 
140 static int
141 geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len)
142 {
143 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
144 
145 	if (len != AES_KEY_LENGTH) {
146 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
147 		return -EINVAL;
148 	}
149 
150 	memcpy(op->key, key, len);
151 	return 0;
152 }
153 
154 static void
155 geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
156 {
157 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
158 
159 	if ((out == NULL) || (in == NULL))
160 		return;
161 
162 	op->src = (void *) in;
163 	op->dst = (void *) out;
164 	op->mode = AES_MODE_ECB;
165 	op->flags = 0;
166 	op->len = AES_MIN_BLOCK_SIZE;
167 	op->dir = AES_DIR_ENCRYPT;
168 
169 	geode_aes_crypt(op);
170 }
171 
172 
173 static void
174 geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
175 {
176 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
177 
178 	if ((out == NULL) || (in == NULL))
179 		return;
180 
181 	op->src = (void *) in;
182 	op->dst = (void *) out;
183 	op->mode = AES_MODE_ECB;
184 	op->flags = 0;
185 	op->len = AES_MIN_BLOCK_SIZE;
186 	op->dir = AES_DIR_DECRYPT;
187 
188 	geode_aes_crypt(op);
189 }
190 
191 
192 static struct crypto_alg geode_alg = {
193 	.cra_name               =       "aes",
194 	.cra_driver_name	=       "geode-aes-128",
195 	.cra_priority           =       300,
196 	.cra_alignmask          =       15,
197 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
198 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
199 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
200 	.cra_module		=	THIS_MODULE,
201 	.cra_list		=	LIST_HEAD_INIT(geode_alg.cra_list),
202 	.cra_u			=	{
203 		.cipher = {
204 			.cia_min_keysize	=  AES_KEY_LENGTH,
205 			.cia_max_keysize	=  AES_KEY_LENGTH,
206 			.cia_setkey		=  geode_setkey,
207 			.cia_encrypt		=  geode_encrypt,
208 			.cia_decrypt		=  geode_decrypt
209 		}
210 	}
211 };
212 
213 static int
214 geode_cbc_decrypt(struct blkcipher_desc *desc,
215 		  struct scatterlist *dst, struct scatterlist *src,
216 		  unsigned int nbytes)
217 {
218 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
219 	struct blkcipher_walk walk;
220 	int err, ret;
221 
222 	blkcipher_walk_init(&walk, dst, src, nbytes);
223 	err = blkcipher_walk_virt(desc, &walk);
224 
225 	while((nbytes = walk.nbytes)) {
226 		op->src = walk.src.virt.addr,
227 		op->dst = walk.dst.virt.addr;
228 		op->mode = AES_MODE_CBC;
229 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
230 		op->dir = AES_DIR_DECRYPT;
231 
232 		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
233 
234 		ret = geode_aes_crypt(op);
235 
236 		memcpy(walk.iv, op->iv, AES_IV_LENGTH);
237 		nbytes -= ret;
238 
239 		err = blkcipher_walk_done(desc, &walk, nbytes);
240 	}
241 
242 	return err;
243 }
244 
245 static int
246 geode_cbc_encrypt(struct blkcipher_desc *desc,
247 		  struct scatterlist *dst, struct scatterlist *src,
248 		  unsigned int nbytes)
249 {
250 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
251 	struct blkcipher_walk walk;
252 	int err, ret;
253 
254 	blkcipher_walk_init(&walk, dst, src, nbytes);
255 	err = blkcipher_walk_virt(desc, &walk);
256 
257 	while((nbytes = walk.nbytes)) {
258 		op->src = walk.src.virt.addr,
259 		op->dst = walk.dst.virt.addr;
260 		op->mode = AES_MODE_CBC;
261 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
262 		op->dir = AES_DIR_ENCRYPT;
263 
264 		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
265 
266 		ret = geode_aes_crypt(op);
267 		nbytes -= ret;
268 		err = blkcipher_walk_done(desc, &walk, nbytes);
269 	}
270 
271 	return err;
272 }
273 
274 static struct crypto_alg geode_cbc_alg = {
275 	.cra_name		=	"cbc(aes)",
276 	.cra_driver_name	=	"cbc-aes-geode-128",
277 	.cra_priority		=	400,
278 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
279 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
280 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
281 	.cra_alignmask		=	15,
282 	.cra_type		=	&crypto_blkcipher_type,
283 	.cra_module		=	THIS_MODULE,
284 	.cra_list		=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
285 	.cra_u			=	{
286 		.blkcipher = {
287 			.min_keysize		=	AES_KEY_LENGTH,
288 			.max_keysize		=	AES_KEY_LENGTH,
289 			.setkey			=	geode_setkey,
290 			.encrypt		=	geode_cbc_encrypt,
291 			.decrypt		=	geode_cbc_decrypt,
292 		}
293 	}
294 };
295 
296 static int
297 geode_ecb_decrypt(struct blkcipher_desc *desc,
298 		  struct scatterlist *dst, struct scatterlist *src,
299 		  unsigned int nbytes)
300 {
301 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
302 	struct blkcipher_walk walk;
303 	int err, ret;
304 
305 	blkcipher_walk_init(&walk, dst, src, nbytes);
306 	err = blkcipher_walk_virt(desc, &walk);
307 
308 	while((nbytes = walk.nbytes)) {
309 		op->src = walk.src.virt.addr,
310 		op->dst = walk.dst.virt.addr;
311 		op->mode = AES_MODE_ECB;
312 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
313 		op->dir = AES_DIR_DECRYPT;
314 
315 		ret = geode_aes_crypt(op);
316 		nbytes -= ret;
317 		err = blkcipher_walk_done(desc, &walk, nbytes);
318 	}
319 
320 	return err;
321 }
322 
323 static int
324 geode_ecb_encrypt(struct blkcipher_desc *desc,
325 		  struct scatterlist *dst, struct scatterlist *src,
326 		  unsigned int nbytes)
327 {
328 	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
329 	struct blkcipher_walk walk;
330 	int err, ret;
331 
332 	blkcipher_walk_init(&walk, dst, src, nbytes);
333 	err = blkcipher_walk_virt(desc, &walk);
334 
335 	while((nbytes = walk.nbytes)) {
336 		op->src = walk.src.virt.addr,
337 		op->dst = walk.dst.virt.addr;
338 		op->mode = AES_MODE_ECB;
339 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
340 		op->dir = AES_DIR_ENCRYPT;
341 
342 		ret = geode_aes_crypt(op);
343 		nbytes -= ret;
344 		ret =  blkcipher_walk_done(desc, &walk, nbytes);
345 	}
346 
347 	return err;
348 }
349 
350 static struct crypto_alg geode_ecb_alg = {
351 	.cra_name		=	"ecb(aes)",
352 	.cra_driver_name	=	"ecb-aes-geode-128",
353 	.cra_priority		=	400,
354 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
355 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
356 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
357 	.cra_alignmask		=	15,
358 	.cra_type		=	&crypto_blkcipher_type,
359 	.cra_module		=	THIS_MODULE,
360 	.cra_list		=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
361 	.cra_u			=	{
362 		.blkcipher = {
363 			.min_keysize		=	AES_KEY_LENGTH,
364 			.max_keysize		=	AES_KEY_LENGTH,
365 			.setkey			=	geode_setkey,
366 			.encrypt		=	geode_ecb_encrypt,
367 			.decrypt		=	geode_ecb_decrypt,
368 		}
369 	}
370 };
371 
372 static void
373 geode_aes_remove(struct pci_dev *dev)
374 {
375 	crypto_unregister_alg(&geode_alg);
376 	crypto_unregister_alg(&geode_ecb_alg);
377 	crypto_unregister_alg(&geode_cbc_alg);
378 
379 	pci_iounmap(dev, _iobase);
380 	_iobase = NULL;
381 
382 	pci_release_regions(dev);
383 	pci_disable_device(dev);
384 }
385 
386 
387 static int
388 geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
389 {
390 	int ret;
391 
392 	if ((ret = pci_enable_device(dev)))
393 		return ret;
394 
395 	if ((ret = pci_request_regions(dev, "geode-aes-128")))
396 		goto eenable;
397 
398 	_iobase = pci_iomap(dev, 0, 0);
399 
400 	if (_iobase == NULL) {
401 		ret = -ENOMEM;
402 		goto erequest;
403 	}
404 
405 	spin_lock_init(&lock);
406 
407 	/* Clear any pending activity */
408 	iowrite32(AES_INTR_PENDING | AES_INTR_MASK, _iobase + AES_INTR_REG);
409 
410 	if ((ret = crypto_register_alg(&geode_alg)))
411 		goto eiomap;
412 
413 	if ((ret = crypto_register_alg(&geode_ecb_alg)))
414 		goto ealg;
415 
416 	if ((ret = crypto_register_alg(&geode_cbc_alg)))
417 		goto eecb;
418 
419 	printk(KERN_NOTICE "geode-aes: GEODE AES engine enabled.\n");
420 	return 0;
421 
422  eecb:
423 	crypto_unregister_alg(&geode_ecb_alg);
424 
425  ealg:
426 	crypto_unregister_alg(&geode_alg);
427 
428  eiomap:
429 	pci_iounmap(dev, _iobase);
430 
431  erequest:
432 	pci_release_regions(dev);
433 
434  eenable:
435 	pci_disable_device(dev);
436 
437 	printk(KERN_ERR "geode-aes:  GEODE AES initialization failed.\n");
438 	return ret;
439 }
440 
441 static struct pci_device_id geode_aes_tbl[] = {
442 	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, PCI_ANY_ID, PCI_ANY_ID} ,
443 	{ 0, }
444 };
445 
446 MODULE_DEVICE_TABLE(pci, geode_aes_tbl);
447 
448 static struct pci_driver geode_aes_driver = {
449 	.name = "Geode LX AES",
450 	.id_table = geode_aes_tbl,
451 	.probe = geode_aes_probe,
452 	.remove = __devexit_p(geode_aes_remove)
453 };
454 
455 static int __init
456 geode_aes_init(void)
457 {
458 	return pci_register_driver(&geode_aes_driver);
459 }
460 
461 static void __exit
462 geode_aes_exit(void)
463 {
464 	pci_unregister_driver(&geode_aes_driver);
465 }
466 
467 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
468 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
469 MODULE_LICENSE("GPL");
470 
471 module_init(geode_aes_init);
472 module_exit(geode_aes_exit);
473