crypto: prefix module autoloading with "crypto-"
[pandora-kernel.git] / arch / s390 / crypto / aes_s390.c
index a9ce135..05d08c8 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include "crypt_s390.h"
 
 #define AES_KEYLEN_128         1
 #define AES_KEYLEN_256         4
 
 static u8 *ctrblk;
+static DEFINE_SPINLOCK(ctrblk_lock);
 static char keylen_flag;
 
 struct s390_aes_ctx {
-       u8 iv[AES_BLOCK_SIZE];
        u8 key[AES_MAX_KEY_SIZE];
        long enc;
        long dec;
@@ -56,8 +57,7 @@ struct pcc_param {
 
 struct s390_xts_ctx {
        u8 key[32];
-       u8 xts_param[16];
-       struct pcc_param pcc;
+       u8 pcc_key[32];
        long enc;
        long dec;
        int key_len;
@@ -326,7 +326,8 @@ static int ecb_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
                u8 *in = walk->src.virt.addr;
 
                ret = crypt_s390_km(func, param, out, in, n);
-               BUG_ON((ret < 0) || (ret != n));
+               if (ret < 0 || ret != n)
+                       return -EIO;
 
                nbytes &= AES_BLOCK_SIZE - 1;
                ret = blkcipher_walk_done(desc, walk, nbytes);
@@ -442,29 +443,36 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
        return aes_set_key(tfm, in_key, key_len);
 }
 
-static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
+static int cbc_aes_crypt(struct blkcipher_desc *desc, long func,
                         struct blkcipher_walk *walk)
 {
+       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
        int ret = blkcipher_walk_virt(desc, walk);
        unsigned int nbytes = walk->nbytes;
+       struct {
+               u8 iv[AES_BLOCK_SIZE];
+               u8 key[AES_MAX_KEY_SIZE];
+       } param;
 
        if (!nbytes)
                goto out;
 
-       memcpy(param, walk->iv, AES_BLOCK_SIZE);
+       memcpy(param.iv, walk->iv, AES_BLOCK_SIZE);
+       memcpy(param.key, sctx->key, sctx->key_len);
        do {
                /* only use complete blocks */
                unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
                u8 *out = walk->dst.virt.addr;
                u8 *in = walk->src.virt.addr;
 
-               ret = crypt_s390_kmc(func, param, out, in, n);
-               BUG_ON((ret < 0) || (ret != n));
+               ret = crypt_s390_kmc(func, &param, out, in, n);
+               if (ret < 0 || ret != n)
+                       return -EIO;
 
                nbytes &= AES_BLOCK_SIZE - 1;
                ret = blkcipher_walk_done(desc, walk, nbytes);
        } while ((nbytes = walk->nbytes));
-       memcpy(walk->iv, param, AES_BLOCK_SIZE);
+       memcpy(walk->iv, param.iv, AES_BLOCK_SIZE);
 
 out:
        return ret;
@@ -481,7 +489,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
                return fallback_blk_enc(desc, dst, src, nbytes);
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
-       return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
+       return cbc_aes_crypt(desc, sctx->enc, &walk);
 }
 
 static int cbc_aes_decrypt(struct blkcipher_desc *desc,
@@ -495,7 +503,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
                return fallback_blk_dec(desc, dst, src, nbytes);
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
-       return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
+       return cbc_aes_crypt(desc, sctx->dec, &walk);
 }
 
 static struct crypto_alg cbc_aes_alg = {
@@ -587,7 +595,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
                xts_ctx->enc = KM_XTS_128_ENCRYPT;
                xts_ctx->dec = KM_XTS_128_DECRYPT;
                memcpy(xts_ctx->key + 16, in_key, 16);
-               memcpy(xts_ctx->pcc.key + 16, in_key + 16, 16);
+               memcpy(xts_ctx->pcc_key + 16, in_key + 16, 16);
                break;
        case 48:
                xts_ctx->enc = 0;
@@ -598,7 +606,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
                xts_ctx->enc = KM_XTS_256_ENCRYPT;
                xts_ctx->dec = KM_XTS_256_DECRYPT;
                memcpy(xts_ctx->key, in_key, 32);
-               memcpy(xts_ctx->pcc.key, in_key + 32, 32);
+               memcpy(xts_ctx->pcc_key, in_key + 32, 32);
                break;
        default:
                *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -617,29 +625,35 @@ static int xts_aes_crypt(struct blkcipher_desc *desc, long func,
        unsigned int nbytes = walk->nbytes;
        unsigned int n;
        u8 *in, *out;
-       void *param;
+       struct pcc_param pcc_param;
+       struct {
+               u8 key[32];
+               u8 init[16];
+       } xts_param;
 
        if (!nbytes)
                goto out;
 
-       memset(xts_ctx->pcc.block, 0, sizeof(xts_ctx->pcc.block));
-       memset(xts_ctx->pcc.bit, 0, sizeof(xts_ctx->pcc.bit));
-       memset(xts_ctx->pcc.xts, 0, sizeof(xts_ctx->pcc.xts));
-       memcpy(xts_ctx->pcc.tweak, walk->iv, sizeof(xts_ctx->pcc.tweak));
-       param = xts_ctx->pcc.key + offset;
-       ret = crypt_s390_pcc(func, param);
-       BUG_ON(ret < 0);
-
-       memcpy(xts_ctx->xts_param, xts_ctx->pcc.xts, 16);
-       param = xts_ctx->key + offset;
+       memset(pcc_param.block, 0, sizeof(pcc_param.block));
+       memset(pcc_param.bit, 0, sizeof(pcc_param.bit));
+       memset(pcc_param.xts, 0, sizeof(pcc_param.xts));
+       memcpy(pcc_param.tweak, walk->iv, sizeof(pcc_param.tweak));
+       memcpy(pcc_param.key, xts_ctx->pcc_key, 32);
+       ret = crypt_s390_pcc(func, &pcc_param.key[offset]);
+       if (ret < 0)
+               return -EIO;
+
+       memcpy(xts_param.key, xts_ctx->key, 32);
+       memcpy(xts_param.init, pcc_param.xts, 16);
        do {
                /* only use complete blocks */
                n = nbytes & ~(AES_BLOCK_SIZE - 1);
                out = walk->dst.virt.addr;
                in = walk->src.virt.addr;
 
-               ret = crypt_s390_km(func, param, out, in, n);
-               BUG_ON(ret < 0 || ret != n);
+               ret = crypt_s390_km(func, &xts_param.key[offset], out, in, n);
+               if (ret < 0 || ret != n)
+                       return -EIO;
 
                nbytes &= AES_BLOCK_SIZE - 1;
                ret = blkcipher_walk_done(desc, walk, nbytes);
@@ -748,42 +762,67 @@ static int ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
        return aes_set_key(tfm, in_key, key_len);
 }
 
+static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes)
+{
+       unsigned int i, n;
+
+       /* only use complete blocks, max. PAGE_SIZE */
+       n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1);
+       for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) {
+               memcpy(ctrptr + i, ctrptr + i - AES_BLOCK_SIZE,
+                      AES_BLOCK_SIZE);
+               crypto_inc(ctrptr + i, AES_BLOCK_SIZE);
+       }
+       return n;
+}
+
 static int ctr_aes_crypt(struct blkcipher_desc *desc, long func,
                         struct s390_aes_ctx *sctx, struct blkcipher_walk *walk)
 {
        int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE);
-       unsigned int i, n, nbytes;
-       u8 buf[AES_BLOCK_SIZE];
-       u8 *out, *in;
+       unsigned int n, nbytes;
+       u8 buf[AES_BLOCK_SIZE], ctrbuf[AES_BLOCK_SIZE];
+       u8 *out, *in, *ctrptr = ctrbuf;
 
        if (!walk->nbytes)
                return ret;
 
-       memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE);
+       if (spin_trylock(&ctrblk_lock))
+               ctrptr = ctrblk;
+
+       memcpy(ctrptr, walk->iv, AES_BLOCK_SIZE);
        while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
                out = walk->dst.virt.addr;
                in = walk->src.virt.addr;
                while (nbytes >= AES_BLOCK_SIZE) {
-                       /* only use complete blocks, max. PAGE_SIZE */
-                       n = (nbytes > PAGE_SIZE) ? PAGE_SIZE :
-                                                nbytes & ~(AES_BLOCK_SIZE - 1);
-                       for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) {
-                               memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE,
-                                      AES_BLOCK_SIZE);
-                               crypto_inc(ctrblk + i, AES_BLOCK_SIZE);
+                       if (ctrptr == ctrblk)
+                               n = __ctrblk_init(ctrptr, nbytes);
+                       else
+                               n = AES_BLOCK_SIZE;
+                       ret = crypt_s390_kmctr(func, sctx->key, out, in,
+                                              n, ctrptr);
+                       if (ret < 0 || ret != n) {
+                               if (ctrptr == ctrblk)
+                                       spin_unlock(&ctrblk_lock);
+                               return -EIO;
                        }
-                       ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk);
-                       BUG_ON(ret < 0 || ret != n);
                        if (n > AES_BLOCK_SIZE)
-                               memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE,
+                               memcpy(ctrptr, ctrptr + n - AES_BLOCK_SIZE,
                                       AES_BLOCK_SIZE);
-                       crypto_inc(ctrblk, AES_BLOCK_SIZE);
+                       crypto_inc(ctrptr, AES_BLOCK_SIZE);
                        out += n;
                        in += n;
                        nbytes -= n;
                }
                ret = blkcipher_walk_done(desc, walk, nbytes);
        }
+       if (ctrptr == ctrblk) {
+               if (nbytes)
+                       memcpy(ctrbuf, ctrptr, AES_BLOCK_SIZE);
+               else
+                       memcpy(walk->iv, ctrptr, AES_BLOCK_SIZE);
+               spin_unlock(&ctrblk_lock);
+       }
        /*
         * final block may be < AES_BLOCK_SIZE, copy only nbytes
         */
@@ -791,13 +830,15 @@ static int ctr_aes_crypt(struct blkcipher_desc *desc, long func,
                out = walk->dst.virt.addr;
                in = walk->src.virt.addr;
                ret = crypt_s390_kmctr(func, sctx->key, buf, in,
-                                      AES_BLOCK_SIZE, ctrblk);
-               BUG_ON(ret < 0 || ret != AES_BLOCK_SIZE);
+                                      AES_BLOCK_SIZE, ctrbuf);
+               if (ret < 0 || ret != AES_BLOCK_SIZE)
+                       return -EIO;
                memcpy(out, buf, nbytes);
-               crypto_inc(ctrblk, AES_BLOCK_SIZE);
+               crypto_inc(ctrbuf, AES_BLOCK_SIZE);
                ret = blkcipher_walk_done(desc, walk, 0);
+               memcpy(walk->iv, ctrbuf, AES_BLOCK_SIZE);
        }
-       memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE);
+
        return ret;
 }
 
@@ -931,7 +972,7 @@ static void __exit aes_s390_fini(void)
 module_init(aes_s390_init);
 module_exit(aes_s390_fini);
 
-MODULE_ALIAS("aes-all");
+MODULE_ALIAS_CRYPTO("aes-all");
 
 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
 MODULE_LICENSE("GPL");