wifi: use buildin instand of ko for compatibility
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / crypto / ghash-ce-glue.c
1 /*
2  * Accelerated GHASH implementation with ARMv8 PMULL instructions.
3  *
4  * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published
8  * by the Free Software Foundation.
9  */
10
11 #include <asm/neon.h>
12 #include <asm/unaligned.h>
13 #include <crypto/internal/hash.h>
14 #include <linux/cpufeature.h>
15 #include <linux/crypto.h>
16 #include <linux/module.h>
17
18 MODULE_DESCRIPTION("GHASH secure hash using ARMv8 Crypto Extensions");
19 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
20 MODULE_LICENSE("GPL v2");
21
22 #define GHASH_BLOCK_SIZE        16
23 #define GHASH_DIGEST_SIZE       16
24
25 struct ghash_key {
26         u64 a;
27         u64 b;
28 };
29
30 struct ghash_desc_ctx {
31         u64 digest[GHASH_DIGEST_SIZE/sizeof(u64)];
32         u8 buf[GHASH_BLOCK_SIZE];
33         u32 count;
34 };
35
36 asmlinkage void pmull_ghash_update(int blocks, u64 dg[], const char *src,
37                                    struct ghash_key const *k, const char *head);
38
39 static int ghash_init(struct shash_desc *desc)
40 {
41         struct ghash_desc_ctx *ctx = shash_desc_ctx(desc);
42
43         *ctx = (struct ghash_desc_ctx){};
44         return 0;
45 }
46
47 static int ghash_update(struct shash_desc *desc, const u8 *src,
48                         unsigned int len)
49 {
50         struct ghash_desc_ctx *ctx = shash_desc_ctx(desc);
51         unsigned int partial = ctx->count % GHASH_BLOCK_SIZE;
52
53         ctx->count += len;
54
55         if ((partial + len) >= GHASH_BLOCK_SIZE) {
56                 struct ghash_key *key = crypto_shash_ctx(desc->tfm);
57                 int blocks;
58
59                 if (partial) {
60                         int p = GHASH_BLOCK_SIZE - partial;
61
62                         memcpy(ctx->buf + partial, src, p);
63                         src += p;
64                         len -= p;
65                 }
66
67                 blocks = len / GHASH_BLOCK_SIZE;
68                 len %= GHASH_BLOCK_SIZE;
69
70                 kernel_neon_begin_partial(6);
71                 pmull_ghash_update(blocks, ctx->digest, src, key,
72                                    partial ? ctx->buf : NULL);
73                 kernel_neon_end();
74                 src += blocks * GHASH_BLOCK_SIZE;
75         }
76         if (len)
77                 memcpy(ctx->buf + partial, src, len);
78         return 0;
79 }
80
81 static int ghash_final(struct shash_desc *desc, u8 *dst)
82 {
83         struct ghash_desc_ctx *ctx = shash_desc_ctx(desc);
84         unsigned int partial = ctx->count % GHASH_BLOCK_SIZE;
85
86         if (partial) {
87                 struct ghash_key *key = crypto_shash_ctx(desc->tfm);
88
89                 memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial);
90
91                 kernel_neon_begin_partial(6);
92                 pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL);
93                 kernel_neon_end();
94         }
95         put_unaligned_be64(ctx->digest[1], dst);
96         put_unaligned_be64(ctx->digest[0], dst + 8);
97
98         *ctx = (struct ghash_desc_ctx){};
99         return 0;
100 }
101
102 static int ghash_setkey(struct crypto_shash *tfm,
103                         const u8 *inkey, unsigned int keylen)
104 {
105         struct ghash_key *key = crypto_shash_ctx(tfm);
106         u64 a, b;
107
108         if (keylen != GHASH_BLOCK_SIZE) {
109                 crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
110                 return -EINVAL;
111         }
112
113         /* perform multiplication by 'x' in GF(2^128) */
114         b = get_unaligned_be64(inkey);
115         a = get_unaligned_be64(inkey + 8);
116
117         key->a = (a << 1) | (b >> 63);
118         key->b = (b << 1) | (a >> 63);
119
120         if (b >> 63)
121                 key->b ^= 0xc200000000000000UL;
122
123         return 0;
124 }
125
126 static struct shash_alg ghash_alg = {
127         .digestsize     = GHASH_DIGEST_SIZE,
128         .init           = ghash_init,
129         .update         = ghash_update,
130         .final          = ghash_final,
131         .setkey         = ghash_setkey,
132         .descsize       = sizeof(struct ghash_desc_ctx),
133         .base           = {
134                 .cra_name               = "ghash",
135                 .cra_driver_name        = "ghash-ce",
136                 .cra_priority           = 200,
137                 .cra_flags              = CRYPTO_ALG_TYPE_SHASH,
138                 .cra_blocksize          = GHASH_BLOCK_SIZE,
139                 .cra_ctxsize            = sizeof(struct ghash_key),
140                 .cra_module             = THIS_MODULE,
141         },
142 };
143
144 static int __init ghash_ce_mod_init(void)
145 {
146         return crypto_register_shash(&ghash_alg);
147 }
148
149 static void __exit ghash_ce_mod_exit(void)
150 {
151         crypto_unregister_shash(&ghash_alg);
152 }
153
154 module_cpu_feature_match(PMULL, ghash_ce_mod_init);
155 module_exit(ghash_ce_mod_exit);