19fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse /* Copyright (C) 2004-2006, Advanced Micro Devices, Inc. 29fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse * 39fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse * This program is free software; you can redistribute it and/or modify 49fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse * it under the terms of the GNU General Public License as published by 59fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse * the Free Software Foundation; either version 2 of the License, or 69fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse * (at your option) any later version. 79fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse */ 89fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 99fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <linux/module.h> 109fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <linux/kernel.h> 119fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <linux/pci.h> 129fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <linux/pci_ids.h> 139fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <linux/crypto.h> 149fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <linux/spinlock.h> 159fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include <crypto/algapi.h> 1689e12654312dddbbdbf17b5adc95b22cb672f947Sebastian Siewior#include <crypto/aes.h> 179fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 1899700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau#include <linux/io.h> 1999700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau#include <linux/delay.h> 209fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 219fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse#include "geode-aes.h" 229fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 239fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse/* Static structures */ 249fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2599700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chaustatic void __iomem *_iobase; 269fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic spinlock_t lock; 279fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 289fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse/* Write a 128 bit field (either a writable key or IV) */ 299fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic inline void 309fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse_writefield(u32 offset, void *value) 319fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 329fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int i; 3399700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau for (i = 0; i < 4; i++) 349fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32(((u32 *) value)[i], _iobase + offset + (i * 4)); 359fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 369fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 379fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse/* Read a 128 bit field (either a writable key or IV) */ 389fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic inline void 399fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse_readfield(u32 offset, void *value) 409fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 419fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int i; 4299700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau for (i = 0; i < 4; i++) 439fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ((u32 *) value)[i] = ioread32(_iobase + offset + (i * 4)); 449fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 459fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 469fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic int 479fe757b0cfcee0724027a675c533077287a21b96Jordan Crousedo_crypt(void *src, void *dst, int len, u32 flags) 489fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 499fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse u32 status; 509fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse u32 counter = AES_OP_TIMEOUT; 519fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 529fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32(virt_to_phys(src), _iobase + AES_SOURCEA_REG); 539fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32(virt_to_phys(dst), _iobase + AES_DSTA_REG); 549fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32(len, _iobase + AES_LENA_REG); 559fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 569fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse /* Start the operation */ 579fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG); 589fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 591f4e4773761d0aa622411469b54d6570005a66b1Sebastian Siewior do { 609fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse status = ioread32(_iobase + AES_INTR_REG); 611f4e4773761d0aa622411469b54d6570005a66b1Sebastian Siewior cpu_relax(); 6299700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau } while (!(status & AES_INTRA_PENDING) && --counter); 639fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 649fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse /* Clear the event */ 659fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG); 669fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return counter ? 0 : 1; 679fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 689fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 69ab7827059adbbcc3624afbc58880287eabf6d277Adrian Bunkstatic unsigned int 709fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_aes_crypt(struct geode_aes_op *op) 719fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 729fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse u32 flags = 0; 735efee174f8a101cafb1607d2b629bed353701457Alexey Dobriyan unsigned long iflags; 741f4e4773761d0aa622411469b54d6570005a66b1Sebastian Siewior int ret; 759fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 76761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse if (op->len == 0) 779fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return 0; 789fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 79761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse /* If the source and destination is the same, then 80761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse * we need to turn on the coherent flags, otherwise 81761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse * we don't need to worry 82761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse */ 83761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse 842e21630ddc3fb717dc645356b75771c6a52dc627Sebastian Siewior flags |= (AES_CTRL_DCA | AES_CTRL_SCA); 859fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 869fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse if (op->dir == AES_DIR_ENCRYPT) 879fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse flags |= AES_CTRL_ENCRYPT; 889fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 899fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse /* Start the critical section */ 909fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 919fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse spin_lock_irqsave(&lock, iflags); 929fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 939fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse if (op->mode == AES_MODE_CBC) { 949fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse flags |= AES_CTRL_CBC; 959fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse _writefield(AES_WRITEIV0_REG, op->iv); 969fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 979fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 98761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse if (!(op->flags & AES_FLAGS_HIDDENKEY)) { 999fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse flags |= AES_CTRL_WRKEY; 1009fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse _writefield(AES_WRITEKEY0_REG, op->key); 1019fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 1029fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 1031f4e4773761d0aa622411469b54d6570005a66b1Sebastian Siewior ret = do_crypt(op->src, op->dst, op->len, flags); 1041f4e4773761d0aa622411469b54d6570005a66b1Sebastian Siewior BUG_ON(ret); 1059fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 1069fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse if (op->mode == AES_MODE_CBC) 1079fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse _readfield(AES_WRITEIV0_REG, op->iv); 1089fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 1099fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse spin_unlock_irqrestore(&lock, iflags); 1109fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 1119fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return op->len; 1129fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 1139fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 1149fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse/* CRYPTO-API Functions */ 1159fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 116cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, 117cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int len) 1189fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 1199fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_tfm_ctx(tfm); 120cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int ret; 121cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 122cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->keylen = len; 123cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 124cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (len == AES_KEYSIZE_128) { 125cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior memcpy(op->key, key, len); 126cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return 0; 127cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 1289fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 129cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { 130cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior /* not supported at all */ 1319fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 1329fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return -EINVAL; 1339fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 1349fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 135cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior /* 136cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior * The requested key size is not supported by HW, do a fallback 137cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior */ 138faad98f29606d9d3c6bddae7c88693be37d2fb43Roel Kluin op->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; 139faad98f29606d9d3c6bddae7c88693be37d2fb43Roel Kluin op->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); 140cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 141cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior ret = crypto_cipher_setkey(op->fallback.cip, key, len); 142cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (ret) { 143cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 144e054f1647162d7098a9ff619405a72bd7c417213Roel Kluin tfm->crt_flags |= (op->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK); 145cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 146cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return ret; 147cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 148cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 149cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key, 150cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int len) 151cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 152cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_tfm_ctx(tfm); 153cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int ret; 154cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 155cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->keylen = len; 156cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 157cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (len == AES_KEYSIZE_128) { 158cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior memcpy(op->key, key, len); 159cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return 0; 160cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 161cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 162cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { 163cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior /* not supported at all */ 164cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 165cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return -EINVAL; 166cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 167cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 168cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior /* 169cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior * The requested key size is not supported by HW, do a fallback 170cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior */ 171cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; 172cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); 173cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 174cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior ret = crypto_blkcipher_setkey(op->fallback.blk, key, len); 175cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (ret) { 176cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 177cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); 178cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 179cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return ret; 180cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 181cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 182cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic int fallback_blk_dec(struct blkcipher_desc *desc, 183cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct scatterlist *dst, struct scatterlist *src, 184cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int nbytes) 185cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 186cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int ret; 187cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct crypto_blkcipher *tfm; 188cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); 189cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 190cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior tfm = desc->tfm; 191cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior desc->tfm = op->fallback.blk; 192cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 193fdc520aa693d462f4958339534a3b596f95795b7Sebastian Siewior ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); 194cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 195cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior desc->tfm = tfm; 196cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return ret; 197cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 198cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic int fallback_blk_enc(struct blkcipher_desc *desc, 199cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct scatterlist *dst, struct scatterlist *src, 200cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int nbytes) 201cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 202cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior unsigned int ret; 203cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct crypto_blkcipher *tfm; 204cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); 205cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 206cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior tfm = desc->tfm; 207cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior desc->tfm = op->fallback.blk; 208cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 209fdc520aa693d462f4958339534a3b596f95795b7Sebastian Siewior ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); 210cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 211cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior desc->tfm = tfm; 212cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return ret; 2139fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 2149fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2159fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic void 2169fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 2179fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 2189fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_tfm_ctx(tfm); 2199fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 220cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (unlikely(op->keylen != AES_KEYSIZE_128)) { 221cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior crypto_cipher_encrypt_one(op->fallback.cip, out, in); 2229fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return; 223cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 2249fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2259fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->src = (void *) in; 2269fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dst = (void *) out; 2279fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->mode = AES_MODE_ECB; 2289fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->flags = 0; 2299fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->len = AES_MIN_BLOCK_SIZE; 2309fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dir = AES_DIR_ENCRYPT; 2319fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2329fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse geode_aes_crypt(op); 2339fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 2349fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2359fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2369fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic void 2379fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 2389fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 2399fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_tfm_ctx(tfm); 2409fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 241cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (unlikely(op->keylen != AES_KEYSIZE_128)) { 242cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior crypto_cipher_decrypt_one(op->fallback.cip, out, in); 2439fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return; 244cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 2459fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2469fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->src = (void *) in; 2479fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dst = (void *) out; 2489fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->mode = AES_MODE_ECB; 2499fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->flags = 0; 2509fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->len = AES_MIN_BLOCK_SIZE; 2519fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dir = AES_DIR_DECRYPT; 2529fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2539fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse geode_aes_crypt(op); 2549fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 2559fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 256cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic int fallback_init_cip(struct crypto_tfm *tfm) 257cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 258cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior const char *name = tfm->__crt_alg->cra_name; 259cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_tfm_ctx(tfm); 260cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 261cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->fallback.cip = crypto_alloc_cipher(name, 0, 262cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); 263cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 264cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (IS_ERR(op->fallback.cip)) { 265cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior printk(KERN_ERR "Error allocating fallback algo %s\n", name); 266faad98f29606d9d3c6bddae7c88693be37d2fb43Roel Kluin return PTR_ERR(op->fallback.cip); 267cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 268cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 269cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return 0; 270cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 271cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 272cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic void fallback_exit_cip(struct crypto_tfm *tfm) 273cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 274cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_tfm_ctx(tfm); 275cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 276cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior crypto_free_cipher(op->fallback.cip); 277cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->fallback.cip = NULL; 278cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 2799fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 2809fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic struct crypto_alg geode_alg = { 281cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_name = "aes", 282cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_driver_name = "geode-aes", 283cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_priority = 300, 284cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_alignmask = 15, 285cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_flags = CRYPTO_ALG_TYPE_CIPHER | 286cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior CRYPTO_ALG_NEED_FALLBACK, 287cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_init = fallback_init_cip, 288cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_exit = fallback_exit_cip, 2899fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_blocksize = AES_MIN_BLOCK_SIZE, 2909fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_ctxsize = sizeof(struct geode_aes_op), 291cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_module = THIS_MODULE, 292cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), 293cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_u = { 294cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cipher = { 295cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cia_min_keysize = AES_MIN_KEY_SIZE, 296cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cia_max_keysize = AES_MAX_KEY_SIZE, 297cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cia_setkey = geode_setkey_cip, 298cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cia_encrypt = geode_encrypt, 299cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cia_decrypt = geode_decrypt 3009fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 3019fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 3029fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse}; 3039fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3049fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic int 3059fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_cbc_decrypt(struct blkcipher_desc *desc, 3069fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct scatterlist *dst, struct scatterlist *src, 3079fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse unsigned int nbytes) 3089fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 3099fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); 3109fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct blkcipher_walk walk; 3119fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int err, ret; 3129fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 313cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (unlikely(op->keylen != AES_KEYSIZE_128)) 314cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return fallback_blk_dec(desc, dst, src, nbytes); 315cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 3169fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse blkcipher_walk_init(&walk, dst, src, nbytes); 3179fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_virt(desc, &walk); 318d2456c66236c15d6462f1ac751cdbd48a34e9704Sebastian Siewior op->iv = walk.iv; 3199fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 32099700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau while ((nbytes = walk.nbytes)) { 3219fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->src = walk.src.virt.addr, 3229fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dst = walk.dst.virt.addr; 3239fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->mode = AES_MODE_CBC; 3249fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); 3259fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dir = AES_DIR_DECRYPT; 3269fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3279fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ret = geode_aes_crypt(op); 3289fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3299fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse nbytes -= ret; 3309fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_done(desc, &walk, nbytes); 3319fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 3329fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3339fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return err; 3349fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 3359fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3369fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic int 3379fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_cbc_encrypt(struct blkcipher_desc *desc, 3389fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct scatterlist *dst, struct scatterlist *src, 3399fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse unsigned int nbytes) 3409fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 3419fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); 3429fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct blkcipher_walk walk; 3439fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int err, ret; 3449fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 345cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (unlikely(op->keylen != AES_KEYSIZE_128)) 346cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return fallback_blk_enc(desc, dst, src, nbytes); 347cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 3489fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse blkcipher_walk_init(&walk, dst, src, nbytes); 3499fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_virt(desc, &walk); 350d2456c66236c15d6462f1ac751cdbd48a34e9704Sebastian Siewior op->iv = walk.iv; 3519fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 35299700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau while ((nbytes = walk.nbytes)) { 3539fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->src = walk.src.virt.addr, 3549fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dst = walk.dst.virt.addr; 3559fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->mode = AES_MODE_CBC; 3569fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); 3579fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dir = AES_DIR_ENCRYPT; 3589fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3599fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ret = geode_aes_crypt(op); 3609fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse nbytes -= ret; 3619fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_done(desc, &walk, nbytes); 3629fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 3639fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 3649fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return err; 3659fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 3669fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 367cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic int fallback_init_blk(struct crypto_tfm *tfm) 368cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 369cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior const char *name = tfm->__crt_alg->cra_name; 370cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_tfm_ctx(tfm); 371cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 372cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->fallback.blk = crypto_alloc_blkcipher(name, 0, 373cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); 374cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 375cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (IS_ERR(op->fallback.blk)) { 376cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior printk(KERN_ERR "Error allocating fallback algo %s\n", name); 377cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return PTR_ERR(op->fallback.blk); 378cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior } 379cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 380cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return 0; 381cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 382cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 383cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewiorstatic void fallback_exit_blk(struct crypto_tfm *tfm) 384cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior{ 385cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior struct geode_aes_op *op = crypto_tfm_ctx(tfm); 386cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 387cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior crypto_free_blkcipher(op->fallback.blk); 388cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior op->fallback.blk = NULL; 389cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior} 390cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 3919fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic struct crypto_alg geode_cbc_alg = { 3929fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_name = "cbc(aes)", 393cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_driver_name = "cbc-aes-geode", 3949fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_priority = 400, 395cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | 396d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY | 397d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos CRYPTO_ALG_NEED_FALLBACK, 398cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_init = fallback_init_blk, 399cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_exit = fallback_exit_blk, 4009fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_blocksize = AES_MIN_BLOCK_SIZE, 4019fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_ctxsize = sizeof(struct geode_aes_op), 4029fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_alignmask = 15, 403cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_type = &crypto_blkcipher_type, 404cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_module = THIS_MODULE, 405cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), 406cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_u = { 407cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .blkcipher = { 408cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .min_keysize = AES_MIN_KEY_SIZE, 409cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .max_keysize = AES_MAX_KEY_SIZE, 410cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .setkey = geode_setkey_blk, 4119fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .encrypt = geode_cbc_encrypt, 4129fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .decrypt = geode_cbc_decrypt, 413761e784673d79c8ea9befdad31e30c65e0d20b82Jordan Crouse .ivsize = AES_IV_LENGTH, 4149fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 4159fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 4169fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse}; 4179fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4189fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic int 4199fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_ecb_decrypt(struct blkcipher_desc *desc, 4209fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct scatterlist *dst, struct scatterlist *src, 4219fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse unsigned int nbytes) 4229fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 4239fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); 4249fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct blkcipher_walk walk; 4259fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int err, ret; 4269fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 427cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (unlikely(op->keylen != AES_KEYSIZE_128)) 428cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return fallback_blk_dec(desc, dst, src, nbytes); 429cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 4309fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse blkcipher_walk_init(&walk, dst, src, nbytes); 4319fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_virt(desc, &walk); 4329fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 43399700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau while ((nbytes = walk.nbytes)) { 4349fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->src = walk.src.virt.addr, 4359fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dst = walk.dst.virt.addr; 4369fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->mode = AES_MODE_ECB; 4379fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); 4389fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dir = AES_DIR_DECRYPT; 4399fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4409fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ret = geode_aes_crypt(op); 4419fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse nbytes -= ret; 4429fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_done(desc, &walk, nbytes); 4439fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 4449fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4459fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return err; 4469fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 4479fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4489fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic int 4499fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_ecb_encrypt(struct blkcipher_desc *desc, 4509fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct scatterlist *dst, struct scatterlist *src, 4519fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse unsigned int nbytes) 4529fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 4539fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); 4549fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse struct blkcipher_walk walk; 4559fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int err, ret; 4569fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 457cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior if (unlikely(op->keylen != AES_KEYSIZE_128)) 458cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior return fallback_blk_enc(desc, dst, src, nbytes); 459cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior 4609fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse blkcipher_walk_init(&walk, dst, src, nbytes); 4619fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse err = blkcipher_walk_virt(desc, &walk); 4629fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 46399700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau while ((nbytes = walk.nbytes)) { 4649fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->src = walk.src.virt.addr, 4659fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dst = walk.dst.virt.addr; 4669fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->mode = AES_MODE_ECB; 4679fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); 4689fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse op->dir = AES_DIR_ENCRYPT; 4699fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4709fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ret = geode_aes_crypt(op); 4719fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse nbytes -= ret; 4729fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ret = blkcipher_walk_done(desc, &walk, nbytes); 4739fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 4749fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4759fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return err; 4769fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 4779fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 4789fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic struct crypto_alg geode_ecb_alg = { 479cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_name = "ecb(aes)", 480cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_driver_name = "ecb-aes-geode", 4819fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_priority = 400, 482cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | 483d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY | 484d912bb7677f46d78a3cde8a4afd45a3fca4b34e9Nikos Mavrogiannopoulos CRYPTO_ALG_NEED_FALLBACK, 485cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_init = fallback_init_blk, 486cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_exit = fallback_exit_blk, 4879fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_blocksize = AES_MIN_BLOCK_SIZE, 4889fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_ctxsize = sizeof(struct geode_aes_op), 4899fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .cra_alignmask = 15, 490cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_type = &crypto_blkcipher_type, 491cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_module = THIS_MODULE, 492cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), 493cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .cra_u = { 494cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .blkcipher = { 495cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .min_keysize = AES_MIN_KEY_SIZE, 496cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .max_keysize = AES_MAX_KEY_SIZE, 497cd7c3bfe54270f41ac52be6b725a7194d99175b4Sebastian Siewior .setkey = geode_setkey_blk, 4989fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .encrypt = geode_ecb_encrypt, 4999fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .decrypt = geode_ecb_decrypt, 5009fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 5019fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 5029fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse}; 5039fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 504f17922bc75d6261dd6e0e2d687ff43b96e91e04aAdrian Bunkstatic void __devexit 5059fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_aes_remove(struct pci_dev *dev) 5069fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 5079fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse crypto_unregister_alg(&geode_alg); 5089fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse crypto_unregister_alg(&geode_ecb_alg); 5099fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse crypto_unregister_alg(&geode_cbc_alg); 5109fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5119fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_iounmap(dev, _iobase); 5129fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse _iobase = NULL; 5139fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5149fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_release_regions(dev); 5159fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_disable_device(dev); 5169fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 5179fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5189fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 519f17922bc75d6261dd6e0e2d687ff43b96e91e04aAdrian Bunkstatic int __devinit 5209fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) 5219fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 5229fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse int ret; 52399700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau ret = pci_enable_device(dev); 52499700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau if (ret) 5259fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return ret; 5269fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 52799700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau ret = pci_request_regions(dev, "geode-aes"); 52899700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau if (ret) 5299fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse goto eenable; 5309fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5319fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse _iobase = pci_iomap(dev, 0, 0); 5329fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5339fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse if (_iobase == NULL) { 5349fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ret = -ENOMEM; 5359fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse goto erequest; 5369fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse } 5379fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5389fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse spin_lock_init(&lock); 5399fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5409fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse /* Clear any pending activity */ 5419fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse iowrite32(AES_INTR_PENDING | AES_INTR_MASK, _iobase + AES_INTR_REG); 5429fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 54399700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau ret = crypto_register_alg(&geode_alg); 54499700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau if (ret) 5459fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse goto eiomap; 5469fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 54799700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau ret = crypto_register_alg(&geode_ecb_alg); 54899700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau if (ret) 5499fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse goto ealg; 5509fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 55199700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau ret = crypto_register_alg(&geode_cbc_alg); 55299700716a9b2e117fd50c6d3f1fd5edeef6dc6d2Chihau Chau if (ret) 5539fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse goto eecb; 5549fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5559fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse printk(KERN_NOTICE "geode-aes: GEODE AES engine enabled.\n"); 5569fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return 0; 5579fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5589fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse eecb: 5599fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse crypto_unregister_alg(&geode_ecb_alg); 5609fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5619fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse ealg: 5629fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse crypto_unregister_alg(&geode_alg); 5639fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5649fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse eiomap: 5659fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_iounmap(dev, _iobase); 5669fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5679fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse erequest: 5689fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_release_regions(dev); 5699fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5709fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse eenable: 5719fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_disable_device(dev); 5729fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5739fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse printk(KERN_ERR "geode-aes: GEODE AES initialization failed.\n"); 5749fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse return ret; 5759fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 5769fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5779fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic struct pci_device_id geode_aes_tbl[] = { 5781fb1defbb00eb2954483a7d9a70f8a02edf51753Peter Huewe { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), } , 5799fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse { 0, } 5809fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse}; 5819fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5829fe757b0cfcee0724027a675c533077287a21b96Jordan CrouseMODULE_DEVICE_TABLE(pci, geode_aes_tbl); 5839fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5849fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic struct pci_driver geode_aes_driver = { 5859fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .name = "Geode LX AES", 5869fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .id_table = geode_aes_tbl, 5879fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .probe = geode_aes_probe, 5889fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse .remove = __devexit_p(geode_aes_remove) 5899fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse}; 5909fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5919fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic int __init 5929fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_aes_init(void) 5939fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 59409cb914f096bd38b22341af291236b65cf55ceeeRichard Knutsson return pci_register_driver(&geode_aes_driver); 5959fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 5969fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 5979fe757b0cfcee0724027a675c533077287a21b96Jordan Crousestatic void __exit 5989fe757b0cfcee0724027a675c533077287a21b96Jordan Crousegeode_aes_exit(void) 5999fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse{ 6009fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse pci_unregister_driver(&geode_aes_driver); 6019fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse} 6029fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 6039fe757b0cfcee0724027a675c533077287a21b96Jordan CrouseMODULE_AUTHOR("Advanced Micro Devices, Inc."); 6049fe757b0cfcee0724027a675c533077287a21b96Jordan CrouseMODULE_DESCRIPTION("Geode LX Hardware AES driver"); 6059fe757b0cfcee0724027a675c533077287a21b96Jordan CrouseMODULE_LICENSE("GPL"); 6069fe757b0cfcee0724027a675c533077287a21b96Jordan Crouse 6079fe757b0cfcee0724027a675c533077287a21b96Jordan Crousemodule_init(geode_aes_init); 6089fe757b0cfcee0724027a675c533077287a21b96Jordan Crousemodule_exit(geode_aes_exit); 609