summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2017-05-24 03:35:31 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2017-06-10 00:04:19 -0400
commitad18cc9d0f911928704cdc37f4d126853daa9e4e (patch)
tree1a16791b6ee2b5fdbe468743c529869c81bb15bc
parentd695bfd6f02adf362511a6d0139e7f7e6342d3e8 (diff)
crypto: omap-aes - Add support for GCM mode
OMAP AES hw supports AES-GCM mode. This patch adds support for GCM and RFC4106 GCM mode in omap-aes driver. The GCM implementation is mostly written into its own source file, which gets built into the same driver binary as the existing AES support. Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com> [t-kristo@ti.com: forward port to latest upstream kernel, conversion to use omap-crypto lib and some additional fixes] Signed-off-by: Tero Kristo <t-kristo@ti.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/crypto/Kconfig1
-rw-r--r--drivers/crypto/Makefile3
-rw-r--r--drivers/crypto/omap-aes-gcm.c408
-rw-r--r--drivers/crypto/omap-aes.c159
-rw-r--r--drivers/crypto/omap-aes.h54
5 files changed, 612 insertions, 13 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 64171cad735d..4e6591b0b128 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -344,6 +344,7 @@ config CRYPTO_DEV_OMAP_AES
344 select CRYPTO_CBC 344 select CRYPTO_CBC
345 select CRYPTO_ECB 345 select CRYPTO_ECB
346 select CRYPTO_CTR 346 select CRYPTO_CTR
347 select CRYPTO_AEAD
347 help 348 help
348 OMAP processors have AES module accelerator. Select this if you 349 OMAP processors have AES module accelerator. Select this if you
349 want to use the OMAP module for AES algorithms. 350 want to use the OMAP module for AES algorithms.
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 8fd11510f6b9..8177388f5c85 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -21,7 +21,8 @@ obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
21n2_crypto-y := n2_core.o n2_asm.o 21n2_crypto-y := n2_core.o n2_asm.o
22obj-$(CONFIG_CRYPTO_DEV_NX) += nx/ 22obj-$(CONFIG_CRYPTO_DEV_NX) += nx/
23obj-$(CONFIG_CRYPTO_DEV_OMAP) += omap-crypto.o 23obj-$(CONFIG_CRYPTO_DEV_OMAP) += omap-crypto.o
24obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o 24obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes-driver.o
25omap-aes-driver-objs := omap-aes.o omap-aes-gcm.o
25obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o 26obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o
26obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o 27obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
27obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o 28obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
diff --git a/drivers/crypto/omap-aes-gcm.c b/drivers/crypto/omap-aes-gcm.c
new file mode 100644
index 000000000000..521a310ea699
--- /dev/null
+++ b/drivers/crypto/omap-aes-gcm.c
@@ -0,0 +1,408 @@
1/*
2 * Cryptographic API.
3 *
4 * Support for OMAP AES GCM HW acceleration.
5 *
6 * Copyright (c) 2016 Texas Instruments Incorporated
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 */
13
14#include <linux/errno.h>
15#include <linux/scatterlist.h>
16#include <linux/dma-mapping.h>
17#include <linux/dmaengine.h>
18#include <linux/omap-dma.h>
19#include <linux/interrupt.h>
20#include <crypto/aes.h>
21#include <crypto/scatterwalk.h>
22#include <crypto/skcipher.h>
23#include <crypto/internal/aead.h>
24
25#include "omap-crypto.h"
26#include "omap-aes.h"
27
28static int omap_aes_gcm_handle_queue(struct omap_aes_dev *dd,
29 struct aead_request *req);
30
31static void omap_aes_gcm_finish_req(struct omap_aes_dev *dd, int ret)
32{
33 struct aead_request *req = dd->aead_req;
34
35 dd->flags &= ~FLAGS_BUSY;
36 dd->in_sg = NULL;
37 dd->out_sg = NULL;
38
39 req->base.complete(&req->base, ret);
40}
41
42static void omap_aes_gcm_done_task(struct omap_aes_dev *dd)
43{
44 u8 *tag;
45 int alen, clen, i, ret = 0, nsg;
46 struct omap_aes_reqctx *rctx;
47
48 alen = ALIGN(dd->assoc_len, AES_BLOCK_SIZE);
49 clen = ALIGN(dd->total, AES_BLOCK_SIZE);
50 rctx = aead_request_ctx(dd->aead_req);
51
52 nsg = !!(dd->assoc_len && dd->total);
53
54 dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len,
55 DMA_FROM_DEVICE);
56 dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
57 dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE);
58 omap_aes_crypt_dma_stop(dd);
59
60 omap_crypto_cleanup(dd->out_sg, dd->orig_out,
61 dd->aead_req->assoclen, dd->total,
62 FLAGS_OUT_DATA_ST_SHIFT, dd->flags);
63
64 if (dd->flags & FLAGS_ENCRYPT)
65 scatterwalk_map_and_copy(rctx->auth_tag,
66 dd->aead_req->dst,
67 dd->total + dd->aead_req->assoclen,
68 dd->authsize, 1);
69
70 omap_crypto_cleanup(&dd->in_sgl[0], NULL, 0, alen,
71 FLAGS_ASSOC_DATA_ST_SHIFT, dd->flags);
72
73 omap_crypto_cleanup(&dd->in_sgl[nsg], NULL, 0, clen,
74 FLAGS_IN_DATA_ST_SHIFT, dd->flags);
75
76 if (!(dd->flags & FLAGS_ENCRYPT)) {
77 tag = (u8 *)rctx->auth_tag;
78 for (i = 0; i < dd->authsize; i++) {
79 if (tag[i]) {
80 dev_err(dd->dev, "GCM decryption: Tag Message is wrong\n");
81 ret = -EBADMSG;
82 }
83 }
84 }
85
86 omap_aes_gcm_finish_req(dd, ret);
87 omap_aes_gcm_handle_queue(dd, NULL);
88}
89
90static int omap_aes_gcm_copy_buffers(struct omap_aes_dev *dd,
91 struct aead_request *req)
92{
93 int alen, clen, cryptlen, assoclen, ret;
94 struct crypto_aead *aead = crypto_aead_reqtfm(req);
95 unsigned int authlen = crypto_aead_authsize(aead);
96 struct scatterlist *tmp, sg_arr[2];
97 int nsg;
98 u16 flags;
99
100 assoclen = req->assoclen;
101 cryptlen = req->cryptlen;
102
103 if (dd->flags & FLAGS_RFC4106_GCM)
104 assoclen -= 8;
105
106 if (!(dd->flags & FLAGS_ENCRYPT))
107 cryptlen -= authlen;
108
109 alen = ALIGN(assoclen, AES_BLOCK_SIZE);
110 clen = ALIGN(cryptlen, AES_BLOCK_SIZE);
111
112 nsg = !!(assoclen && cryptlen);
113
114 omap_aes_clear_copy_flags(dd);
115
116 sg_init_table(dd->in_sgl, nsg + 1);
117 if (assoclen) {
118 tmp = req->src;
119 ret = omap_crypto_align_sg(&tmp, assoclen,
120 AES_BLOCK_SIZE, dd->in_sgl,
121 OMAP_CRYPTO_COPY_DATA |
122 OMAP_CRYPTO_ZERO_BUF |
123 OMAP_CRYPTO_FORCE_SINGLE_ENTRY,
124 FLAGS_ASSOC_DATA_ST_SHIFT,
125 &dd->flags);
126 }
127
128 if (cryptlen) {
129 tmp = scatterwalk_ffwd(sg_arr, req->src, req->assoclen);
130
131 ret = omap_crypto_align_sg(&tmp, cryptlen,
132 AES_BLOCK_SIZE, &dd->in_sgl[nsg],
133 OMAP_CRYPTO_COPY_DATA |
134 OMAP_CRYPTO_ZERO_BUF |
135 OMAP_CRYPTO_FORCE_SINGLE_ENTRY,
136 FLAGS_IN_DATA_ST_SHIFT,
137 &dd->flags);
138 }
139
140 dd->in_sg = dd->in_sgl;
141 dd->total = cryptlen;
142 dd->assoc_len = assoclen;
143 dd->authsize = authlen;
144
145 dd->out_sg = req->dst;
146 dd->orig_out = req->dst;
147
148 dd->out_sg = scatterwalk_ffwd(sg_arr, req->dst, assoclen);
149
150 flags = 0;
151 if (req->src == req->dst || dd->out_sg == sg_arr)
152 flags |= OMAP_CRYPTO_FORCE_COPY;
153
154 ret = omap_crypto_align_sg(&dd->out_sg, cryptlen,
155 AES_BLOCK_SIZE, &dd->out_sgl,
156 flags,
157 FLAGS_OUT_DATA_ST_SHIFT, &dd->flags);
158 if (ret)
159 return ret;
160
161 dd->in_sg_len = sg_nents_for_len(dd->in_sg, alen + clen);
162 dd->out_sg_len = sg_nents_for_len(dd->out_sg, clen);
163
164 return 0;
165}
166
167static void omap_aes_gcm_complete(struct crypto_async_request *req, int err)
168{
169 struct omap_aes_gcm_result *res = req->data;
170
171 if (err == -EINPROGRESS)
172 return;
173
174 res->err = err;
175 complete(&res->completion);
176}
177
178static int do_encrypt_iv(struct aead_request *req, u32 *tag, u32 *iv)
179{
180 struct scatterlist iv_sg, tag_sg;
181 struct skcipher_request *sk_req;
182 struct omap_aes_gcm_result result;
183 struct omap_aes_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
184 int ret = 0;
185
186 sk_req = skcipher_request_alloc(ctx->ctr, GFP_KERNEL);
187 if (!sk_req) {
188 pr_err("skcipher: Failed to allocate request\n");
189 return -1;
190 }
191
192 init_completion(&result.completion);
193
194 sg_init_one(&iv_sg, iv, AES_BLOCK_SIZE);
195 sg_init_one(&tag_sg, tag, AES_BLOCK_SIZE);
196 skcipher_request_set_callback(sk_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
197 omap_aes_gcm_complete, &result);
198 ret = crypto_skcipher_setkey(ctx->ctr, (u8 *)ctx->key, ctx->keylen);
199 skcipher_request_set_crypt(sk_req, &iv_sg, &tag_sg, AES_BLOCK_SIZE,
200 NULL);
201 ret = crypto_skcipher_encrypt(sk_req);
202 switch (ret) {
203 case 0:
204 break;
205 case -EINPROGRESS:
206 case -EBUSY:
207 ret = wait_for_completion_interruptible(&result.completion);
208 if (!ret) {
209 ret = result.err;
210 if (!ret) {
211 reinit_completion(&result.completion);
212 break;
213 }
214 }
215 /* fall through */
216 default:
217 pr_err("Encryptio of IV failed for GCM mode");
218 break;
219 }
220
221 skcipher_request_free(sk_req);
222 return ret;
223}
224
225void omap_aes_gcm_dma_out_callback(void *data)
226{
227 struct omap_aes_dev *dd = data;
228 struct omap_aes_reqctx *rctx;
229 int i, val;
230 u32 *auth_tag, tag[4];
231
232 if (!(dd->flags & FLAGS_ENCRYPT))
233 scatterwalk_map_and_copy(tag, dd->aead_req->src,
234 dd->total + dd->aead_req->assoclen,
235 dd->authsize, 0);
236
237 rctx = aead_request_ctx(dd->aead_req);
238 auth_tag = (u32 *)rctx->auth_tag;
239 for (i = 0; i < 4; i++) {
240 val = omap_aes_read(dd, AES_REG_TAG_N(dd, i));
241 auth_tag[i] = val ^ auth_tag[i];
242 if (!(dd->flags & FLAGS_ENCRYPT))
243 auth_tag[i] = auth_tag[i] ^ tag[i];
244 }
245
246 omap_aes_gcm_done_task(dd);
247}
248
249static int omap_aes_gcm_handle_queue(struct omap_aes_dev *dd,
250 struct aead_request *req)
251{
252 struct omap_aes_ctx *ctx;
253 struct aead_request *backlog;
254 struct omap_aes_reqctx *rctx;
255 unsigned long flags;
256 int err, ret = 0;
257
258 spin_lock_irqsave(&dd->lock, flags);
259 if (req)
260 ret = aead_enqueue_request(&dd->aead_queue, req);
261 if (dd->flags & FLAGS_BUSY) {
262 spin_unlock_irqrestore(&dd->lock, flags);
263 return ret;
264 }
265
266 backlog = aead_get_backlog(&dd->aead_queue);
267 req = aead_dequeue_request(&dd->aead_queue);
268 if (req)
269 dd->flags |= FLAGS_BUSY;
270 spin_unlock_irqrestore(&dd->lock, flags);
271
272 if (!req)
273 return ret;
274
275 if (backlog)
276 backlog->base.complete(&backlog->base, -EINPROGRESS);
277
278 ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
279 rctx = aead_request_ctx(req);
280
281 dd->ctx = ctx;
282 rctx->dd = dd;
283 dd->aead_req = req;
284
285 rctx->mode &= FLAGS_MODE_MASK;
286 dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
287
288 err = omap_aes_gcm_copy_buffers(dd, req);
289 if (err)
290 return err;
291
292 err = omap_aes_write_ctrl(dd);
293 if (!err)
294 err = omap_aes_crypt_dma_start(dd);
295
296 if (err) {
297 omap_aes_gcm_finish_req(dd, err);
298 omap_aes_gcm_handle_queue(dd, NULL);
299 }
300
301 return ret;
302}
303
304static int omap_aes_gcm_crypt(struct aead_request *req, unsigned long mode)
305{
306 struct omap_aes_reqctx *rctx = aead_request_ctx(req);
307 struct crypto_aead *aead = crypto_aead_reqtfm(req);
308 unsigned int authlen = crypto_aead_authsize(aead);
309 struct omap_aes_dev *dd;
310 __be32 counter = cpu_to_be32(1);
311 int err, assoclen;
312
313 memset(rctx->auth_tag, 0, sizeof(rctx->auth_tag));
314 memcpy(rctx->iv + 12, &counter, 4);
315
316 err = do_encrypt_iv(req, (u32 *)rctx->auth_tag, (u32 *)rctx->iv);
317 if (err)
318 return err;
319
320 if (mode & FLAGS_RFC4106_GCM)
321 assoclen = req->assoclen - 8;
322 else
323 assoclen = req->assoclen;
324 if (assoclen + req->cryptlen == 0) {
325 scatterwalk_map_and_copy(rctx->auth_tag, req->dst, 0, authlen,
326 1);
327 return 0;
328 }
329
330 dd = omap_aes_find_dev(rctx);
331 if (!dd)
332 return -ENODEV;
333 rctx->mode = mode;
334
335 return omap_aes_gcm_handle_queue(dd, req);
336}
337
338int omap_aes_gcm_encrypt(struct aead_request *req)
339{
340 struct omap_aes_reqctx *rctx = aead_request_ctx(req);
341
342 memcpy(rctx->iv, req->iv, 12);
343 return omap_aes_gcm_crypt(req, FLAGS_ENCRYPT | FLAGS_GCM);
344}
345
346int omap_aes_gcm_decrypt(struct aead_request *req)
347{
348 struct omap_aes_reqctx *rctx = aead_request_ctx(req);
349
350 memcpy(rctx->iv, req->iv, 12);
351 return omap_aes_gcm_crypt(req, FLAGS_GCM);
352}
353
354int omap_aes_4106gcm_encrypt(struct aead_request *req)
355{
356 struct omap_aes_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
357 struct omap_aes_reqctx *rctx = aead_request_ctx(req);
358
359 memcpy(rctx->iv, ctx->nonce, 4);
360 memcpy(rctx->iv + 4, req->iv, 8);
361 return omap_aes_gcm_crypt(req, FLAGS_ENCRYPT | FLAGS_GCM |
362 FLAGS_RFC4106_GCM);
363}
364
365int omap_aes_4106gcm_decrypt(struct aead_request *req)
366{
367 struct omap_aes_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
368 struct omap_aes_reqctx *rctx = aead_request_ctx(req);
369
370 memcpy(rctx->iv, ctx->nonce, 4);
371 memcpy(rctx->iv + 4, req->iv, 8);
372 return omap_aes_gcm_crypt(req, FLAGS_GCM | FLAGS_RFC4106_GCM);
373}
374
375int omap_aes_gcm_setkey(struct crypto_aead *tfm, const u8 *key,
376 unsigned int keylen)
377{
378 struct omap_aes_ctx *ctx = crypto_aead_ctx(tfm);
379
380 if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
381 keylen != AES_KEYSIZE_256)
382 return -EINVAL;
383
384 memcpy(ctx->key, key, keylen);
385 ctx->keylen = keylen;
386
387 return 0;
388}
389
390int omap_aes_4106gcm_setkey(struct crypto_aead *tfm, const u8 *key,
391 unsigned int keylen)
392{
393 struct omap_aes_ctx *ctx = crypto_aead_ctx(tfm);
394
395 if (keylen < 4)
396 return -EINVAL;
397
398 keylen -= 4;
399 if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
400 keylen != AES_KEYSIZE_256)
401 return -EINVAL;
402
403 memcpy(ctx->key, key, keylen);
404 memcpy(ctx->nonce, key + keylen, 4);
405 ctx->keylen = keylen;
406
407 return 0;
408}
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index bf3b27d9dc33..5120a17731d0 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -37,6 +37,7 @@
37#include <crypto/aes.h> 37#include <crypto/aes.h>
38#include <crypto/engine.h> 38#include <crypto/engine.h>
39#include <crypto/internal/skcipher.h> 39#include <crypto/internal/skcipher.h>
40#include <crypto/internal/aead.h>
40 41
41#include "omap-crypto.h" 42#include "omap-crypto.h"
42#include "omap-aes.h" 43#include "omap-aes.h"
@@ -112,8 +113,16 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd)
112 return 0; 113 return 0;
113} 114}
114 115
116void omap_aes_clear_copy_flags(struct omap_aes_dev *dd)
117{
118 dd->flags &= ~(OMAP_CRYPTO_COPY_MASK << FLAGS_IN_DATA_ST_SHIFT);
119 dd->flags &= ~(OMAP_CRYPTO_COPY_MASK << FLAGS_OUT_DATA_ST_SHIFT);
120 dd->flags &= ~(OMAP_CRYPTO_COPY_MASK << FLAGS_ASSOC_DATA_ST_SHIFT);
121}
122
115int omap_aes_write_ctrl(struct omap_aes_dev *dd) 123int omap_aes_write_ctrl(struct omap_aes_dev *dd)
116{ 124{
125 struct omap_aes_reqctx *rctx;
117 unsigned int key32; 126 unsigned int key32;
118 int i, err; 127 int i, err;
119 u32 val; 128 u32 val;
@@ -124,7 +133,11 @@ int omap_aes_write_ctrl(struct omap_aes_dev *dd)
124 133
125 key32 = dd->ctx->keylen / sizeof(u32); 134 key32 = dd->ctx->keylen / sizeof(u32);
126 135
127 /* it seems a key should always be set even if it has not changed */ 136 /* RESET the key as previous HASH keys should not get affected*/
137 if (dd->flags & FLAGS_GCM)
138 for (i = 0; i < 0x40; i = i + 4)
139 omap_aes_write(dd, i, 0x0);
140
128 for (i = 0; i < key32; i++) { 141 for (i = 0; i < key32; i++) {
129 omap_aes_write(dd, AES_REG_KEY(dd, i), 142 omap_aes_write(dd, AES_REG_KEY(dd, i),
130 __le32_to_cpu(dd->ctx->key[i])); 143 __le32_to_cpu(dd->ctx->key[i]));
@@ -133,12 +146,21 @@ int omap_aes_write_ctrl(struct omap_aes_dev *dd)
133 if ((dd->flags & (FLAGS_CBC | FLAGS_CTR)) && dd->req->info) 146 if ((dd->flags & (FLAGS_CBC | FLAGS_CTR)) && dd->req->info)
134 omap_aes_write_n(dd, AES_REG_IV(dd, 0), dd->req->info, 4); 147 omap_aes_write_n(dd, AES_REG_IV(dd, 0), dd->req->info, 4);
135 148
149 if ((dd->flags & (FLAGS_GCM)) && dd->aead_req->iv) {
150 rctx = aead_request_ctx(dd->aead_req);
151 omap_aes_write_n(dd, AES_REG_IV(dd, 0), (u32 *)rctx->iv, 4);
152 }
153
136 val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); 154 val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
137 if (dd->flags & FLAGS_CBC) 155 if (dd->flags & FLAGS_CBC)
138 val |= AES_REG_CTRL_CBC; 156 val |= AES_REG_CTRL_CBC;
139 if (dd->flags & FLAGS_CTR) 157
158 if (dd->flags & (FLAGS_CTR | FLAGS_GCM))
140 val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_128; 159 val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_128;
141 160
161 if (dd->flags & FLAGS_GCM)
162 val |= AES_REG_CTRL_GCM;
163
142 if (dd->flags & FLAGS_ENCRYPT) 164 if (dd->flags & FLAGS_ENCRYPT)
143 val |= AES_REG_CTRL_DIRECTION; 165 val |= AES_REG_CTRL_DIRECTION;
144 166
@@ -169,6 +191,8 @@ static void omap_aes_dma_trigger_omap4(struct omap_aes_dev *dd, int length)
169{ 191{
170 omap_aes_write(dd, AES_REG_LENGTH_N(0), length); 192 omap_aes_write(dd, AES_REG_LENGTH_N(0), length);
171 omap_aes_write(dd, AES_REG_LENGTH_N(1), 0); 193 omap_aes_write(dd, AES_REG_LENGTH_N(1), 0);
194 if (dd->flags & FLAGS_GCM)
195 omap_aes_write(dd, AES_REG_A_LEN, dd->assoc_len);
172 196
173 omap_aes_dma_trigger_omap2(dd, length); 197 omap_aes_dma_trigger_omap2(dd, length);
174} 198}
@@ -306,7 +330,10 @@ static int omap_aes_crypt_dma(struct omap_aes_dev *dd,
306 return -EINVAL; 330 return -EINVAL;
307 } 331 }
308 332
309 tx_out->callback = omap_aes_dma_out_callback; 333 if (dd->flags & FLAGS_GCM)
334 tx_out->callback = omap_aes_gcm_dma_out_callback;
335 else
336 tx_out->callback = omap_aes_dma_out_callback;
310 tx_out->callback_param = dd; 337 tx_out->callback_param = dd;
311 338
312 dmaengine_submit(tx_in); 339 dmaengine_submit(tx_in);
@@ -411,7 +438,7 @@ static int omap_aes_prepare_req(struct crypto_engine *engine,
411 flags |= OMAP_CRYPTO_FORCE_COPY; 438 flags |= OMAP_CRYPTO_FORCE_COPY;
412 439
413 ret = omap_crypto_align_sg(&dd->in_sg, dd->total, AES_BLOCK_SIZE, 440 ret = omap_crypto_align_sg(&dd->in_sg, dd->total, AES_BLOCK_SIZE,
414 &dd->in_sgl, flags, 441 dd->in_sgl, flags,
415 FLAGS_IN_DATA_ST_SHIFT, &dd->flags); 442 FLAGS_IN_DATA_ST_SHIFT, &dd->flags);
416 if (ret) 443 if (ret)
417 return ret; 444 return ret;
@@ -466,7 +493,7 @@ static void omap_aes_done_task(unsigned long data)
466 omap_aes_crypt_dma_stop(dd); 493 omap_aes_crypt_dma_stop(dd);
467 } 494 }
468 495
469 omap_crypto_cleanup(&dd->in_sgl, NULL, 0, dd->total_save, 496 omap_crypto_cleanup(dd->in_sgl, NULL, 0, dd->total_save,
470 FLAGS_IN_DATA_ST_SHIFT, dd->flags); 497 FLAGS_IN_DATA_ST_SHIFT, dd->flags);
471 498
472 omap_crypto_cleanup(&dd->out_sgl, dd->orig_out, 0, dd->total_save, 499 omap_crypto_cleanup(&dd->out_sgl, dd->orig_out, 0, dd->total_save,
@@ -591,6 +618,36 @@ static int omap_aes_cra_init(struct crypto_tfm *tfm)
591 return 0; 618 return 0;
592} 619}
593 620
621static int omap_aes_gcm_cra_init(struct crypto_aead *tfm)
622{
623 struct omap_aes_dev *dd = NULL;
624 struct omap_aes_ctx *ctx = crypto_aead_ctx(tfm);
625 int err;
626
627 /* Find AES device, currently picks the first device */
628 spin_lock_bh(&list_lock);
629 list_for_each_entry(dd, &dev_list, list) {
630 break;
631 }
632 spin_unlock_bh(&list_lock);
633
634 err = pm_runtime_get_sync(dd->dev);
635 if (err < 0) {
636 dev_err(dd->dev, "%s: failed to get_sync(%d)\n",
637 __func__, err);
638 return err;
639 }
640
641 tfm->reqsize = sizeof(struct omap_aes_reqctx);
642 ctx->ctr = crypto_alloc_skcipher("ecb(aes)", 0, 0);
643 if (IS_ERR(ctx->ctr)) {
644 pr_warn("could not load aes driver for encrypting IV\n");
645 return PTR_ERR(ctx->ctr);
646 }
647
648 return 0;
649}
650
594static void omap_aes_cra_exit(struct crypto_tfm *tfm) 651static void omap_aes_cra_exit(struct crypto_tfm *tfm)
595{ 652{
596 struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); 653 struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -601,6 +658,16 @@ static void omap_aes_cra_exit(struct crypto_tfm *tfm)
601 ctx->fallback = NULL; 658 ctx->fallback = NULL;
602} 659}
603 660
661static void omap_aes_gcm_cra_exit(struct crypto_aead *tfm)
662{
663 struct omap_aes_ctx *ctx = crypto_aead_ctx(tfm);
664
665 omap_aes_cra_exit(crypto_aead_tfm(tfm));
666
667 if (ctx->ctr)
668 crypto_free_skcipher(ctx->ctr);
669}
670
604/* ********************** ALGS ************************************ */ 671/* ********************** ALGS ************************************ */
605 672
606static struct crypto_alg algs_ecb_cbc[] = { 673static struct crypto_alg algs_ecb_cbc[] = {
@@ -685,6 +752,54 @@ static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc[] = {
685 }, 752 },
686}; 753};
687 754
755static struct aead_alg algs_aead_gcm[] = {
756{
757 .base = {
758 .cra_name = "gcm(aes)",
759 .cra_driver_name = "gcm-aes-omap",
760 .cra_priority = 300,
761 .cra_flags = CRYPTO_ALG_ASYNC |
762 CRYPTO_ALG_KERN_DRIVER_ONLY,
763 .cra_blocksize = 1,
764 .cra_ctxsize = sizeof(struct omap_aes_ctx),
765 .cra_alignmask = 0xf,
766 .cra_module = THIS_MODULE,
767 },
768 .init = omap_aes_gcm_cra_init,
769 .exit = omap_aes_gcm_cra_exit,
770 .ivsize = 12,
771 .maxauthsize = AES_BLOCK_SIZE,
772 .setkey = omap_aes_gcm_setkey,
773 .encrypt = omap_aes_gcm_encrypt,
774 .decrypt = omap_aes_gcm_decrypt,
775},
776{
777 .base = {
778 .cra_name = "rfc4106(gcm(aes))",
779 .cra_driver_name = "rfc4106-gcm-aes-omap",
780 .cra_priority = 300,
781 .cra_flags = CRYPTO_ALG_ASYNC |
782 CRYPTO_ALG_KERN_DRIVER_ONLY,
783 .cra_blocksize = 1,
784 .cra_ctxsize = sizeof(struct omap_aes_ctx),
785 .cra_alignmask = 0xf,
786 .cra_module = THIS_MODULE,
787 },
788 .init = omap_aes_gcm_cra_init,
789 .exit = omap_aes_gcm_cra_exit,
790 .maxauthsize = AES_BLOCK_SIZE,
791 .ivsize = 8,
792 .setkey = omap_aes_4106gcm_setkey,
793 .encrypt = omap_aes_4106gcm_encrypt,
794 .decrypt = omap_aes_4106gcm_decrypt,
795},
796};
797
798static struct omap_aes_aead_algs omap_aes_aead_info = {
799 .algs_list = algs_aead_gcm,
800 .size = ARRAY_SIZE(algs_aead_gcm),
801};
802
688static const struct omap_aes_pdata omap_aes_pdata_omap2 = { 803static const struct omap_aes_pdata omap_aes_pdata_omap2 = {
689 .algs_info = omap_aes_algs_info_ecb_cbc, 804 .algs_info = omap_aes_algs_info_ecb_cbc,
690 .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc), 805 .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc),
@@ -738,6 +853,7 @@ static const struct omap_aes_pdata omap_aes_pdata_omap3 = {
738static const struct omap_aes_pdata omap_aes_pdata_omap4 = { 853static const struct omap_aes_pdata omap_aes_pdata_omap4 = {
739 .algs_info = omap_aes_algs_info_ecb_cbc_ctr, 854 .algs_info = omap_aes_algs_info_ecb_cbc_ctr,
740 .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr), 855 .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr),
856 .aead_algs_info = &omap_aes_aead_info,
741 .trigger = omap_aes_dma_trigger_omap4, 857 .trigger = omap_aes_dma_trigger_omap4,
742 .key_ofs = 0x3c, 858 .key_ofs = 0x3c,
743 .iv_ofs = 0x40, 859 .iv_ofs = 0x40,
@@ -920,6 +1036,7 @@ static int omap_aes_probe(struct platform_device *pdev)
920 struct device *dev = &pdev->dev; 1036 struct device *dev = &pdev->dev;
921 struct omap_aes_dev *dd; 1037 struct omap_aes_dev *dd;
922 struct crypto_alg *algp; 1038 struct crypto_alg *algp;
1039 struct aead_alg *aalg;
923 struct resource res; 1040 struct resource res;
924 int err = -ENOMEM, i, j, irq = -1; 1041 int err = -ENOMEM, i, j, irq = -1;
925 u32 reg; 1042 u32 reg;
@@ -932,6 +1049,8 @@ static int omap_aes_probe(struct platform_device *pdev)
932 dd->dev = dev; 1049 dd->dev = dev;
933 platform_set_drvdata(pdev, dd); 1050 platform_set_drvdata(pdev, dd);
934 1051
1052 aead_init_queue(&dd->aead_queue, OMAP_AES_QUEUE_LENGTH);
1053
935 err = (dev->of_node) ? omap_aes_get_res_of(dd, dev, &res) : 1054 err = (dev->of_node) ? omap_aes_get_res_of(dd, dev, &res) :
936 omap_aes_get_res_pdev(dd, pdev, &res); 1055 omap_aes_get_res_pdev(dd, pdev, &res);
937 if (err) 1056 if (err)
@@ -987,6 +1106,7 @@ static int omap_aes_probe(struct platform_device *pdev)
987 } 1106 }
988 } 1107 }
989 1108
1109 spin_lock_init(&dd->lock);
990 1110
991 INIT_LIST_HEAD(&dd->list); 1111 INIT_LIST_HEAD(&dd->list);
992 spin_lock(&list_lock); 1112 spin_lock(&list_lock);
@@ -1023,7 +1143,29 @@ static int omap_aes_probe(struct platform_device *pdev)
1023 } 1143 }
1024 } 1144 }
1025 1145
1146 if (dd->pdata->aead_algs_info &&
1147 !dd->pdata->aead_algs_info->registered) {
1148 for (i = 0; i < dd->pdata->aead_algs_info->size; i++) {
1149 aalg = &dd->pdata->aead_algs_info->algs_list[i];
1150 algp = &aalg->base;
1151
1152 pr_debug("reg alg: %s\n", algp->cra_name);
1153 INIT_LIST_HEAD(&algp->cra_list);
1154
1155 err = crypto_register_aead(aalg);
1156 if (err)
1157 goto err_aead_algs;
1158
1159 dd->pdata->aead_algs_info->registered++;
1160 }
1161 }
1162
1026 return 0; 1163 return 0;
1164err_aead_algs:
1165 for (i = dd->pdata->aead_algs_info->registered - 1; i >= 0; i--) {
1166 aalg = &dd->pdata->aead_algs_info->algs_list[i];
1167 crypto_unregister_aead(aalg);
1168 }
1027err_algs: 1169err_algs:
1028 for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 1170 for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
1029 for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 1171 for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
@@ -1048,6 +1190,7 @@ err_data:
1048static int omap_aes_remove(struct platform_device *pdev) 1190static int omap_aes_remove(struct platform_device *pdev)
1049{ 1191{
1050 struct omap_aes_dev *dd = platform_get_drvdata(pdev); 1192 struct omap_aes_dev *dd = platform_get_drvdata(pdev);
1193 struct aead_alg *aalg;
1051 int i, j; 1194 int i, j;
1052 1195
1053 if (!dd) 1196 if (!dd)
@@ -1062,7 +1205,13 @@ static int omap_aes_remove(struct platform_device *pdev)
1062 crypto_unregister_alg( 1205 crypto_unregister_alg(
1063 &dd->pdata->algs_info[i].algs_list[j]); 1206 &dd->pdata->algs_info[i].algs_list[j]);
1064 1207
1208 for (i = dd->pdata->aead_algs_info->size - 1; i >= 0; i--) {
1209 aalg = &dd->pdata->aead_algs_info->algs_list[i];
1210 crypto_unregister_aead(aalg);
1211 }
1212
1065 crypto_engine_exit(dd->engine); 1213 crypto_engine_exit(dd->engine);
1214
1066 tasklet_kill(&dd->done_task); 1215 tasklet_kill(&dd->done_task);
1067 omap_aes_dma_cleanup(dd); 1216 omap_aes_dma_cleanup(dd);
1068 pm_runtime_disable(dd->dev); 1217 pm_runtime_disable(dd->dev);
diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h
index 11e1784cc4a5..8906342e2b9a 100644
--- a/drivers/crypto/omap-aes.h
+++ b/drivers/crypto/omap-aes.h
@@ -30,11 +30,13 @@
30#define AES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) 30#define AES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04))
31 31
32#define AES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) 32#define AES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs)
33#define AES_REG_CTRL_CONTEXT_READY BIT(31)
33#define AES_REG_CTRL_CTR_WIDTH_MASK GENMASK(8, 7) 34#define AES_REG_CTRL_CTR_WIDTH_MASK GENMASK(8, 7)
34#define AES_REG_CTRL_CTR_WIDTH_32 0 35#define AES_REG_CTRL_CTR_WIDTH_32 0
35#define AES_REG_CTRL_CTR_WIDTH_64 BIT(7) 36#define AES_REG_CTRL_CTR_WIDTH_64 BIT(7)
36#define AES_REG_CTRL_CTR_WIDTH_96 BIT(8) 37#define AES_REG_CTRL_CTR_WIDTH_96 BIT(8)
37#define AES_REG_CTRL_CTR_WIDTH_128 GENMASK(8, 7) 38#define AES_REG_CTRL_CTR_WIDTH_128 GENMASK(8, 7)
39#define AES_REG_CTRL_GCM GENMASK(17, 16)
38#define AES_REG_CTRL_CTR BIT(6) 40#define AES_REG_CTRL_CTR BIT(6)
39#define AES_REG_CTRL_CBC BIT(5) 41#define AES_REG_CTRL_CBC BIT(5)
40#define AES_REG_CTRL_KEY_SIZE GENMASK(4, 3) 42#define AES_REG_CTRL_KEY_SIZE GENMASK(4, 3)
@@ -43,7 +45,12 @@
43#define AES_REG_CTRL_OUTPUT_READY BIT(0) 45#define AES_REG_CTRL_OUTPUT_READY BIT(0)
44#define AES_REG_CTRL_MASK GENMASK(24, 2) 46#define AES_REG_CTRL_MASK GENMASK(24, 2)
45 47
48#define AES_REG_C_LEN_0 0x54
49#define AES_REG_C_LEN_1 0x58
50#define AES_REG_A_LEN 0x5C
51
46#define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) 52#define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04))
53#define AES_REG_TAG_N(dd, x) (0x70 + ((x) * 0x04))
47 54
48#define AES_REG_REV(dd) ((dd)->pdata->rev_ofs) 55#define AES_REG_REV(dd) ((dd)->pdata->rev_ofs)
49 56
@@ -65,30 +72,41 @@
65 72
66#define DEFAULT_AUTOSUSPEND_DELAY 1000 73#define DEFAULT_AUTOSUSPEND_DELAY 1000
67 74
68#define FLAGS_MODE_MASK 0x000f 75#define FLAGS_MODE_MASK 0x001f
69#define FLAGS_ENCRYPT BIT(0) 76#define FLAGS_ENCRYPT BIT(0)
70#define FLAGS_CBC BIT(1) 77#define FLAGS_CBC BIT(1)
71#define FLAGS_GIV BIT(2) 78#define FLAGS_CTR BIT(2)
72#define FLAGS_CTR BIT(3) 79#define FLAGS_GCM BIT(3)
80#define FLAGS_RFC4106_GCM BIT(4)
73 81
74#define FLAGS_INIT BIT(4) 82#define FLAGS_INIT BIT(5)
75#define FLAGS_FAST BIT(5) 83#define FLAGS_FAST BIT(6)
76#define FLAGS_BUSY BIT(6) 84#define FLAGS_BUSY BIT(7)
77 85
78#define FLAGS_IN_DATA_ST_SHIFT 8 86#define FLAGS_IN_DATA_ST_SHIFT 8
79#define FLAGS_OUT_DATA_ST_SHIFT 10 87#define FLAGS_OUT_DATA_ST_SHIFT 10
88#define FLAGS_ASSOC_DATA_ST_SHIFT 12
80 89
81#define AES_BLOCK_WORDS (AES_BLOCK_SIZE >> 2) 90#define AES_BLOCK_WORDS (AES_BLOCK_SIZE >> 2)
82 91
92struct omap_aes_gcm_result {
93 struct completion completion;
94 int err;
95};
96
83struct omap_aes_ctx { 97struct omap_aes_ctx {
84 int keylen; 98 int keylen;
85 u32 key[AES_KEYSIZE_256 / sizeof(u32)]; 99 u32 key[AES_KEYSIZE_256 / sizeof(u32)];
100 u8 nonce[4];
86 struct crypto_skcipher *fallback; 101 struct crypto_skcipher *fallback;
102 struct crypto_skcipher *ctr;
87}; 103};
88 104
89struct omap_aes_reqctx { 105struct omap_aes_reqctx {
90 struct omap_aes_dev *dd; 106 struct omap_aes_dev *dd;
91 unsigned long mode; 107 unsigned long mode;
108 u8 iv[AES_BLOCK_SIZE];
109 u32 auth_tag[AES_BLOCK_SIZE / sizeof(u32)];
92}; 110};
93 111
94#define OMAP_AES_QUEUE_LENGTH 1 112#define OMAP_AES_QUEUE_LENGTH 1
@@ -100,9 +118,16 @@ struct omap_aes_algs_info {
100 unsigned int registered; 118 unsigned int registered;
101}; 119};
102 120
121struct omap_aes_aead_algs {
122 struct aead_alg *algs_list;
123 unsigned int size;
124 unsigned int registered;
125};
126
103struct omap_aes_pdata { 127struct omap_aes_pdata {
104 struct omap_aes_algs_info *algs_info; 128 struct omap_aes_algs_info *algs_info;
105 unsigned int algs_info_size; 129 unsigned int algs_info_size;
130 struct omap_aes_aead_algs *aead_algs_info;
106 131
107 void (*trigger)(struct omap_aes_dev *dd, int length); 132 void (*trigger)(struct omap_aes_dev *dd, int length);
108 133
@@ -135,8 +160,11 @@ struct omap_aes_dev {
135 int err; 160 int err;
136 161
137 struct tasklet_struct done_task; 162 struct tasklet_struct done_task;
163 struct aead_queue aead_queue;
164 spinlock_t lock;
138 165
139 struct ablkcipher_request *req; 166 struct ablkcipher_request *req;
167 struct aead_request *aead_req;
140 struct crypto_engine *engine; 168 struct crypto_engine *engine;
141 169
142 /* 170 /*
@@ -145,12 +173,14 @@ struct omap_aes_dev {
145 */ 173 */
146 size_t total; 174 size_t total;
147 size_t total_save; 175 size_t total_save;
176 size_t assoc_len;
177 size_t authsize;
148 178
149 struct scatterlist *in_sg; 179 struct scatterlist *in_sg;
150 struct scatterlist *out_sg; 180 struct scatterlist *out_sg;
151 181
152 /* Buffers for copying for unaligned cases */ 182 /* Buffers for copying for unaligned cases */
153 struct scatterlist in_sgl; 183 struct scatterlist in_sgl[2];
154 struct scatterlist out_sgl; 184 struct scatterlist out_sgl;
155 struct scatterlist *orig_out; 185 struct scatterlist *orig_out;
156 186
@@ -167,8 +197,18 @@ struct omap_aes_dev {
167u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset); 197u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset);
168void omap_aes_write(struct omap_aes_dev *dd, u32 offset, u32 value); 198void omap_aes_write(struct omap_aes_dev *dd, u32 offset, u32 value);
169struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_reqctx *rctx); 199struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_reqctx *rctx);
200int omap_aes_gcm_setkey(struct crypto_aead *tfm, const u8 *key,
201 unsigned int keylen);
202int omap_aes_4106gcm_setkey(struct crypto_aead *tfm, const u8 *key,
203 unsigned int keylen);
204int omap_aes_gcm_encrypt(struct aead_request *req);
205int omap_aes_gcm_decrypt(struct aead_request *req);
206int omap_aes_4106gcm_encrypt(struct aead_request *req);
207int omap_aes_4106gcm_decrypt(struct aead_request *req);
170int omap_aes_write_ctrl(struct omap_aes_dev *dd); 208int omap_aes_write_ctrl(struct omap_aes_dev *dd);
171int omap_aes_crypt_dma_start(struct omap_aes_dev *dd); 209int omap_aes_crypt_dma_start(struct omap_aes_dev *dd);
172int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd); 210int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd);
211void omap_aes_gcm_dma_out_callback(void *data);
212void omap_aes_clear_copy_flags(struct omap_aes_dev *dd);
173 213
174#endif 214#endif