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