1 /* Copyright (C) 2004-2006, Advanced Micro Devices, Inc.
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.
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>
19 #include <asm/delay.h>
21 #include "geode-aes.h"
23 /* Register definitions */
25 #define AES_CTRLA_REG 0x0000
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
35 #define AES_INTR_REG 0x0008
37 #define AES_INTRA_PENDING (1 << 16)
38 #define AES_INTRB_PENDING (1 << 17)
40 #define AES_INTR_PENDING (AES_INTRA_PENDING | AES_INTRB_PENDING)
41 #define AES_INTR_MASK 0x07
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
49 /* A very large counter that is used to gracefully bail out of an
50 * operation in case of trouble
53 #define AES_OP_TIMEOUT 0x50000
55 /* Static structures */
57 static void __iomem
* _iobase
;
58 static spinlock_t lock
;
60 /* Write a 128 bit field (either a writable key or IV) */
62 _writefield(u32 offset
, void *value
)
65 for(i
= 0; i
< 4; i
++)
66 iowrite32(((u32
*) value
)[i
], _iobase
+ offset
+ (i
* 4));
69 /* Read a 128 bit field (either a writable key or IV) */
71 _readfield(u32 offset
, void *value
)
74 for(i
= 0; i
< 4; i
++)
75 ((u32
*) value
)[i
] = ioread32(_iobase
+ offset
+ (i
* 4));
79 do_crypt(void *src
, void *dst
, int len
, u32 flags
)
82 u32 counter
= AES_OP_TIMEOUT
;
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
);
88 /* Start the operation */
89 iowrite32(AES_CTRL_START
| flags
, _iobase
+ AES_CTRLA_REG
);
92 status
= ioread32(_iobase
+ AES_INTR_REG
);
94 } while(!(status
& AES_INTRA_PENDING
) && --counter
);
97 iowrite32((status
& 0xFF) | AES_INTRA_PENDING
, _iobase
+ AES_INTR_REG
);
98 return counter
? 0 : 1;
102 geode_aes_crypt(struct geode_aes_op
*op
)
105 unsigned long iflags
;
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
116 flags
|= (AES_CTRL_DCA
| AES_CTRL_SCA
);
118 if (op
->dir
== AES_DIR_ENCRYPT
)
119 flags
|= AES_CTRL_ENCRYPT
;
121 /* Start the critical section */
123 spin_lock_irqsave(&lock
, iflags
);
125 if (op
->mode
== AES_MODE_CBC
) {
126 flags
|= AES_CTRL_CBC
;
127 _writefield(AES_WRITEIV0_REG
, op
->iv
);
130 if (!(op
->flags
& AES_FLAGS_HIDDENKEY
)) {
131 flags
|= AES_CTRL_WRKEY
;
132 _writefield(AES_WRITEKEY0_REG
, op
->key
);
135 ret
= do_crypt(op
->src
, op
->dst
, op
->len
, flags
);
138 if (op
->mode
== AES_MODE_CBC
)
139 _readfield(AES_WRITEIV0_REG
, op
->iv
);
141 spin_unlock_irqrestore(&lock
, iflags
);
146 /* CRYPTO-API Functions */
149 geode_setkey(struct crypto_tfm
*tfm
, const u8
*key
, unsigned int len
)
151 struct geode_aes_op
*op
= crypto_tfm_ctx(tfm
);
153 if (len
!= AES_KEY_LENGTH
) {
154 tfm
->crt_flags
|= CRYPTO_TFM_RES_BAD_KEY_LEN
;
158 memcpy(op
->key
, key
, len
);
163 geode_encrypt(struct crypto_tfm
*tfm
, u8
*out
, const u8
*in
)
165 struct geode_aes_op
*op
= crypto_tfm_ctx(tfm
);
167 if ((out
== NULL
) || (in
== NULL
))
170 op
->src
= (void *) in
;
171 op
->dst
= (void *) out
;
172 op
->mode
= AES_MODE_ECB
;
174 op
->len
= AES_MIN_BLOCK_SIZE
;
175 op
->dir
= AES_DIR_ENCRYPT
;
182 geode_decrypt(struct crypto_tfm
*tfm
, u8
*out
, const u8
*in
)
184 struct geode_aes_op
*op
= crypto_tfm_ctx(tfm
);
186 if ((out
== NULL
) || (in
== NULL
))
189 op
->src
= (void *) in
;
190 op
->dst
= (void *) out
;
191 op
->mode
= AES_MODE_ECB
;
193 op
->len
= AES_MIN_BLOCK_SIZE
;
194 op
->dir
= AES_DIR_DECRYPT
;
200 static struct crypto_alg geode_alg
= {
202 .cra_driver_name
= "geode-aes-128",
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
),
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
222 geode_cbc_decrypt(struct blkcipher_desc
*desc
,
223 struct scatterlist
*dst
, struct scatterlist
*src
,
226 struct geode_aes_op
*op
= crypto_blkcipher_ctx(desc
->tfm
);
227 struct blkcipher_walk walk
;
230 blkcipher_walk_init(&walk
, dst
, src
, nbytes
);
231 err
= blkcipher_walk_virt(desc
, &walk
);
232 memcpy(op
->iv
, walk
.iv
, AES_IV_LENGTH
);
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
;
241 ret
= geode_aes_crypt(op
);
244 err
= blkcipher_walk_done(desc
, &walk
, nbytes
);
247 memcpy(walk
.iv
, op
->iv
, AES_IV_LENGTH
);
252 geode_cbc_encrypt(struct blkcipher_desc
*desc
,
253 struct scatterlist
*dst
, struct scatterlist
*src
,
256 struct geode_aes_op
*op
= crypto_blkcipher_ctx(desc
->tfm
);
257 struct blkcipher_walk walk
;
260 blkcipher_walk_init(&walk
, dst
, src
, nbytes
);
261 err
= blkcipher_walk_virt(desc
, &walk
);
262 memcpy(op
->iv
, walk
.iv
, AES_IV_LENGTH
);
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
;
271 ret
= geode_aes_crypt(op
);
273 err
= blkcipher_walk_done(desc
, &walk
, nbytes
);
276 memcpy(walk
.iv
, op
->iv
, AES_IV_LENGTH
);
280 static struct crypto_alg geode_cbc_alg
= {
281 .cra_name
= "cbc(aes)",
282 .cra_driver_name
= "cbc-aes-geode-128",
284 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
285 .cra_blocksize
= AES_MIN_BLOCK_SIZE
,
286 .cra_ctxsize
= sizeof(struct geode_aes_op
),
288 .cra_type
= &crypto_blkcipher_type
,
289 .cra_module
= THIS_MODULE
,
290 .cra_list
= LIST_HEAD_INIT(geode_cbc_alg
.cra_list
),
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
,
304 geode_ecb_decrypt(struct blkcipher_desc
*desc
,
305 struct scatterlist
*dst
, struct scatterlist
*src
,
308 struct geode_aes_op
*op
= crypto_blkcipher_ctx(desc
->tfm
);
309 struct blkcipher_walk walk
;
312 blkcipher_walk_init(&walk
, dst
, src
, nbytes
);
313 err
= blkcipher_walk_virt(desc
, &walk
);
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
;
322 ret
= geode_aes_crypt(op
);
324 err
= blkcipher_walk_done(desc
, &walk
, nbytes
);
331 geode_ecb_encrypt(struct blkcipher_desc
*desc
,
332 struct scatterlist
*dst
, struct scatterlist
*src
,
335 struct geode_aes_op
*op
= crypto_blkcipher_ctx(desc
->tfm
);
336 struct blkcipher_walk walk
;
339 blkcipher_walk_init(&walk
, dst
, src
, nbytes
);
340 err
= blkcipher_walk_virt(desc
, &walk
);
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
;
349 ret
= geode_aes_crypt(op
);
351 ret
= blkcipher_walk_done(desc
, &walk
, nbytes
);
357 static struct crypto_alg geode_ecb_alg
= {
358 .cra_name
= "ecb(aes)",
359 .cra_driver_name
= "ecb-aes-geode-128",
361 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
362 .cra_blocksize
= AES_MIN_BLOCK_SIZE
,
363 .cra_ctxsize
= sizeof(struct geode_aes_op
),
365 .cra_type
= &crypto_blkcipher_type
,
366 .cra_module
= THIS_MODULE
,
367 .cra_list
= LIST_HEAD_INIT(geode_ecb_alg
.cra_list
),
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
,
380 geode_aes_remove(struct pci_dev
*dev
)
382 crypto_unregister_alg(&geode_alg
);
383 crypto_unregister_alg(&geode_ecb_alg
);
384 crypto_unregister_alg(&geode_cbc_alg
);
386 pci_iounmap(dev
, _iobase
);
389 pci_release_regions(dev
);
390 pci_disable_device(dev
);
395 geode_aes_probe(struct pci_dev
*dev
, const struct pci_device_id
*id
)
399 if ((ret
= pci_enable_device(dev
)))
402 if ((ret
= pci_request_regions(dev
, "geode-aes-128")))
405 _iobase
= pci_iomap(dev
, 0, 0);
407 if (_iobase
== NULL
) {
412 spin_lock_init(&lock
);
414 /* Clear any pending activity */
415 iowrite32(AES_INTR_PENDING
| AES_INTR_MASK
, _iobase
+ AES_INTR_REG
);
417 if ((ret
= crypto_register_alg(&geode_alg
)))
420 if ((ret
= crypto_register_alg(&geode_ecb_alg
)))
423 if ((ret
= crypto_register_alg(&geode_cbc_alg
)))
426 printk(KERN_NOTICE
"geode-aes: GEODE AES engine enabled.\n");
430 crypto_unregister_alg(&geode_ecb_alg
);
433 crypto_unregister_alg(&geode_alg
);
436 pci_iounmap(dev
, _iobase
);
439 pci_release_regions(dev
);
442 pci_disable_device(dev
);
444 printk(KERN_ERR
"geode-aes: GEODE AES initialization failed.\n");
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
} ,
453 MODULE_DEVICE_TABLE(pci
, geode_aes_tbl
);
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
)
465 return pci_register_driver(&geode_aes_driver
);
471 pci_unregister_driver(&geode_aes_driver
);
474 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
475 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
476 MODULE_LICENSE("GPL");
478 module_init(geode_aes_init
);
479 module_exit(geode_aes_exit
);