Merge ../linus
[pandora-kernel.git] / crypto / tcrypt.c
index 6863941..e52f56c 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 #include <linux/string.h>
 #include <linux/crypto.h>
 #include <linux/highmem.h>
@@ -86,7 +86,6 @@ static void hexdump(unsigned char *buf, unsigned int len)
 static void test_hash(char *algo, struct hash_testvec *template,
                      unsigned int tcount)
 {
-       char *p;
        unsigned int i, j, k, temp;
        struct scatterlist sg[8];
        char result[64];
@@ -116,10 +115,7 @@ static void test_hash(char *algo, struct hash_testvec *template,
                printk("test %u:\n", i + 1);
                memset(result, 0, 64);
 
-               p = hash_tv[i].plaintext;
-               sg[0].page = virt_to_page(p);
-               sg[0].offset = offset_in_page(p);
-               sg[0].length = hash_tv[i].psize;
+               sg_set_buf(&sg[0], hash_tv[i].plaintext, hash_tv[i].psize);
 
                crypto_digest_init(tfm);
                if (tfm->crt_u.digest.dit_setkey) {
@@ -154,10 +150,8 @@ static void test_hash(char *algo, struct hash_testvec *template,
                                       hash_tv[i].plaintext + temp,
                                       hash_tv[i].tap[k]);
                                temp += hash_tv[i].tap[k];
-                               p = &xbuf[IDX[k]];
-                               sg[k].page = virt_to_page(p);
-                               sg[k].offset = offset_in_page(p);
-                               sg[k].length = hash_tv[i].tap[k];
+                               sg_set_buf(&sg[k], &xbuf[IDX[k]],
+                                           hash_tv[i].tap[k]);
                        }
 
                        crypto_digest_digest(tfm, sg, hash_tv[i].np, result);
@@ -179,7 +173,6 @@ static void test_hash(char *algo, struct hash_testvec *template,
 static void test_hmac(char *algo, struct hmac_testvec *template,
                      unsigned int tcount)
 {
-       char *p;
        unsigned int i, j, k, temp;
        struct scatterlist sg[8];
        char result[64];
@@ -210,11 +203,8 @@ static void test_hmac(char *algo, struct hmac_testvec *template,
                printk("test %u:\n", i + 1);
                memset(result, 0, sizeof (result));
 
-               p = hmac_tv[i].plaintext;
                klen = hmac_tv[i].ksize;
-               sg[0].page = virt_to_page(p);
-               sg[0].offset = offset_in_page(p);
-               sg[0].length = hmac_tv[i].psize;
+               sg_set_buf(&sg[0], hmac_tv[i].plaintext, hmac_tv[i].psize);
 
                crypto_hmac(tfm, hmac_tv[i].key, &klen, sg, 1, result);
 
@@ -243,10 +233,8 @@ static void test_hmac(char *algo, struct hmac_testvec *template,
                                       hmac_tv[i].plaintext + temp,
                                       hmac_tv[i].tap[k]);
                                temp += hmac_tv[i].tap[k];
-                               p = &xbuf[IDX[k]];
-                               sg[k].page = virt_to_page(p);
-                               sg[k].offset = offset_in_page(p);
-                               sg[k].length = hmac_tv[i].tap[k];
+                               sg_set_buf(&sg[k], &xbuf[IDX[k]],
+                                           hmac_tv[i].tap[k]);
                        }
 
                        crypto_hmac(tfm, hmac_tv[i].key, &klen, sg,
@@ -270,7 +258,7 @@ static void test_cipher(char *algo, int mode, int enc,
 {
        unsigned int ret, i, j, k, temp;
        unsigned int tsize;
-       char *p, *q;
+       char *q;
        struct crypto_tfm *tfm;
        char *key;
        struct cipher_testvec *cipher_tv;
@@ -330,10 +318,8 @@ static void test_cipher(char *algo, int mode, int enc,
                                        goto out;
                        }
 
-                       p = cipher_tv[i].input;
-                       sg[0].page = virt_to_page(p);
-                       sg[0].offset = offset_in_page(p);
-                       sg[0].length = cipher_tv[i].ilen;
+                       sg_set_buf(&sg[0], cipher_tv[i].input,
+                                  cipher_tv[i].ilen);
 
                        if (!mode) {
                                crypto_cipher_set_iv(tfm, cipher_tv[i].iv,
@@ -389,10 +375,8 @@ static void test_cipher(char *algo, int mode, int enc,
                                       cipher_tv[i].input + temp,
                                       cipher_tv[i].tap[k]);
                                temp += cipher_tv[i].tap[k];
-                               p = &xbuf[IDX[k]];
-                               sg[k].page = virt_to_page(p);
-                               sg[k].offset = offset_in_page(p);
-                               sg[k].length = cipher_tv[i].tap[k];
+                               sg_set_buf(&sg[k], &xbuf[IDX[k]],
+                                          cipher_tv[i].tap[k]);
                        }
 
                        if (!mode) {
@@ -431,14 +415,12 @@ out:
 static int test_cipher_jiffies(struct crypto_tfm *tfm, int enc, char *p,
                               int blen, int sec)
 {
-       struct scatterlist sg[8];
+       struct scatterlist sg[1];
        unsigned long start, end;
        int bcount;
        int ret;
 
-       sg[0].page = virt_to_page(p);
-       sg[0].offset = offset_in_page(p);
-       sg[0].length = blen;
+       sg_set_buf(sg, p, blen);
 
        for (start = jiffies, end = start + sec * HZ, bcount = 0;
             time_before(jiffies, end); bcount++) {
@@ -459,14 +441,12 @@ static int test_cipher_jiffies(struct crypto_tfm *tfm, int enc, char *p,
 static int test_cipher_cycles(struct crypto_tfm *tfm, int enc, char *p,
                              int blen)
 {
-       struct scatterlist sg[8];
+       struct scatterlist sg[1];
        unsigned long cycles = 0;
        int ret = 0;
        int i;
 
-       sg[0].page = virt_to_page(p);
-       sg[0].offset = offset_in_page(p);
-       sg[0].length = blen;
+       sg_set_buf(sg, p, blen);
 
        local_bh_disable();
        local_irq_disable();
@@ -590,6 +570,122 @@ out:
        crypto_free_tfm(tfm);
 }
 
+static void test_digest_jiffies(struct crypto_tfm *tfm, char *p, int blen,
+                               int plen, char *out, int sec)
+{
+       struct scatterlist sg[1];
+       unsigned long start, end;
+       int bcount, pcount;
+
+       for (start = jiffies, end = start + sec * HZ, bcount = 0;
+            time_before(jiffies, end); bcount++) {
+               crypto_digest_init(tfm);
+               for (pcount = 0; pcount < blen; pcount += plen) {
+                       sg_set_buf(sg, p + pcount, plen);
+                       crypto_digest_update(tfm, sg, 1);
+               }
+               /* we assume there is enough space in 'out' for the result */
+               crypto_digest_final(tfm, out);
+       }
+
+       printk("%6u opers/sec, %9lu bytes/sec\n",
+              bcount / sec, ((long)bcount * blen) / sec);
+
+       return;
+}
+
+static void test_digest_cycles(struct crypto_tfm *tfm, char *p, int blen,
+                              int plen, char *out)
+{
+       struct scatterlist sg[1];
+       unsigned long cycles = 0;
+       int i, pcount;
+
+       local_bh_disable();
+       local_irq_disable();
+
+       /* Warm-up run. */
+       for (i = 0; i < 4; i++) {
+               crypto_digest_init(tfm);
+               for (pcount = 0; pcount < blen; pcount += plen) {
+                       sg_set_buf(sg, p + pcount, plen);
+                       crypto_digest_update(tfm, sg, 1);
+               }
+               crypto_digest_final(tfm, out);
+       }
+
+       /* The real thing. */
+       for (i = 0; i < 8; i++) {
+               cycles_t start, end;
+
+               crypto_digest_init(tfm);
+
+               start = get_cycles();
+
+               for (pcount = 0; pcount < blen; pcount += plen) {
+                       sg_set_buf(sg, p + pcount, plen);
+                       crypto_digest_update(tfm, sg, 1);
+               }
+               crypto_digest_final(tfm, out);
+
+               end = get_cycles();
+
+               cycles += end - start;
+       }
+
+       local_irq_enable();
+       local_bh_enable();
+
+       printk("%6lu cycles/operation, %4lu cycles/byte\n",
+              cycles / 8, cycles / (8 * blen));
+
+       return;
+}
+
+static void test_digest_speed(char *algo, unsigned int sec,
+                             struct digest_speed *speed)
+{
+       struct crypto_tfm *tfm;
+       char output[1024];
+       int i;
+
+       printk("\ntesting speed of %s\n", algo);
+
+       tfm = crypto_alloc_tfm(algo, 0);
+
+       if (tfm == NULL) {
+               printk("failed to load transform for %s\n", algo);
+               return;
+       }
+
+       if (crypto_tfm_alg_digestsize(tfm) > sizeof(output)) {
+               printk("digestsize(%u) > outputbuffer(%zu)\n",
+                      crypto_tfm_alg_digestsize(tfm), sizeof(output));
+               goto out;
+       }
+
+       for (i = 0; speed[i].blen != 0; i++) {
+               if (speed[i].blen > TVMEMSIZE) {
+                       printk("template (%u) too big for tvmem (%u)\n",
+                              speed[i].blen, TVMEMSIZE);
+                       goto out;
+               }
+
+               printk("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ",
+                      i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen);
+
+               memset(tvmem, 0xff, speed[i].blen);
+
+               if (sec)
+                       test_digest_jiffies(tfm, tvmem, speed[i].blen, speed[i].plen, output, sec);
+               else
+                       test_digest_cycles(tfm, tvmem, speed[i].blen, speed[i].plen, output);
+       }
+
+out:
+       crypto_free_tfm(tfm);
+}
+
 static void test_deflate(void)
 {
        unsigned int i;
@@ -709,9 +805,7 @@ static void test_crc32c(void)
        for (i = 0; i < NUMVEC; i++) {
                for (j = 0; j < VECSIZE; j++)
                        test_vec[i][j] = ++b;
-               sg[i].page = virt_to_page(test_vec[i]);
-               sg[i].offset = offset_in_page(test_vec[i]);
-               sg[i].length = VECSIZE;
+               sg_set_buf(&sg[i], test_vec[i], VECSIZE);
        }
 
        seed = SEEDTESTVAL;
@@ -827,6 +921,8 @@ static void do_test(void)
                //AES
                test_cipher ("aes", MODE_ECB, ENCRYPT, aes_enc_tv_template, AES_ENC_TEST_VECTORS);
                test_cipher ("aes", MODE_ECB, DECRYPT, aes_dec_tv_template, AES_DEC_TEST_VECTORS);
+               test_cipher ("aes", MODE_CBC, ENCRYPT, aes_cbc_enc_tv_template, AES_CBC_ENC_TEST_VECTORS);
+               test_cipher ("aes", MODE_CBC, DECRYPT, aes_cbc_dec_tv_template, AES_CBC_DEC_TEST_VECTORS);
 
                //CAST5
                test_cipher ("cast5", MODE_ECB, ENCRYPT, cast5_enc_tv_template, CAST5_ENC_TEST_VECTORS);
@@ -932,6 +1028,8 @@ static void do_test(void)
        case 10:
                test_cipher ("aes", MODE_ECB, ENCRYPT, aes_enc_tv_template, AES_ENC_TEST_VECTORS);
                test_cipher ("aes", MODE_ECB, DECRYPT, aes_dec_tv_template, AES_DEC_TEST_VECTORS);
+               test_cipher ("aes", MODE_CBC, ENCRYPT, aes_cbc_enc_tv_template, AES_CBC_ENC_TEST_VECTORS);
+               test_cipher ("aes", MODE_CBC, DECRYPT, aes_cbc_dec_tv_template, AES_CBC_DEC_TEST_VECTORS);
                break;
 
        case 11:
@@ -1104,6 +1202,60 @@ static void do_test(void)
                                  des_speed_template);
                break;
 
+       case 300:
+               /* fall through */
+
+       case 301:
+               test_digest_speed("md4", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 302:
+               test_digest_speed("md5", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 303:
+               test_digest_speed("sha1", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 304:
+               test_digest_speed("sha256", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 305:
+               test_digest_speed("sha384", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 306:
+               test_digest_speed("sha512", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 307:
+               test_digest_speed("wp256", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 308:
+               test_digest_speed("wp384", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 309:
+               test_digest_speed("wp512", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 310:
+               test_digest_speed("tgr128", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 311:
+               test_digest_speed("tgr160", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 312:
+               test_digest_speed("tgr192", sec, generic_digest_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 399:
+               break;
+
        case 1000:
                test_available();
                break;
@@ -1131,7 +1283,14 @@ static int __init init(void)
 
        kfree(xbuf);
        kfree(tvmem);
-       return 0;
+
+       /* We intentionaly return -EAGAIN to prevent keeping
+        * the module. It does all its work from init()
+        * and doesn't offer any runtime functionality 
+        * => we don't need it in the memory, do we?
+        *                                        -- mludvig
+        */
+       return -EAGAIN;
 }
 
 /*