geode-aes.c revision 1f4e4773761d0aa622411469b54d6570005a66b1
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 57static void __iomem * _iobase; 58static spinlock_t lock; 59 60/* Write a 128 bit field (either a writable key or IV) */ 61static 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) */ 70static 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 78static int 79do_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 101static unsigned int 102geode_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 148static int 149geode_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 162static void 163geode_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 181static void 182geode_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 200static 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 221static int 222geode_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 251static int 252geode_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 280static 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 303static int 304geode_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 330static int 331geode_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 357static 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 379static void 380geode_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 394static int 395geode_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 448static 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 453MODULE_DEVICE_TABLE(pci, geode_aes_tbl); 454 455static 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 462static int __init 463geode_aes_init(void) 464{ 465 return pci_register_driver(&geode_aes_driver); 466} 467 468static void __exit 469geode_aes_exit(void) 470{ 471 pci_unregister_driver(&geode_aes_driver); 472} 473 474MODULE_AUTHOR("Advanced Micro Devices, Inc."); 475MODULE_DESCRIPTION("Geode LX Hardware AES driver"); 476MODULE_LICENSE("GPL"); 477 478module_init(geode_aes_init); 479module_exit(geode_aes_exit); 480