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