1 // SPDX-License-Identifier: GPL-2.0-only
5 * Support for OMAP AES GCM HW acceleration.
7 * Copyright (c) 2016 Texas Instruments Incorporated
10 #include <linux/errno.h>
11 #include <linux/scatterlist.h>
12 #include <linux/dma-mapping.h>
13 #include <linux/dmaengine.h>
14 #include <linux/omap-dma.h>
15 #include <linux/interrupt.h>
16 #include <linux/pm_runtime.h>
17 #include <crypto/aes.h>
18 #include <crypto/gcm.h>
19 #include <crypto/scatterwalk.h>
20 #include <crypto/skcipher.h>
21 #include <crypto/internal/aead.h>
23 #include "omap-crypto.h"
26 static int omap_aes_gcm_handle_queue(struct omap_aes_dev
*dd
,
27 struct aead_request
*req
);
29 static void omap_aes_gcm_finish_req(struct omap_aes_dev
*dd
, int ret
)
31 struct aead_request
*req
= dd
->aead_req
;
36 crypto_finalize_aead_request(dd
->engine
, req
, ret
);
38 pm_runtime_mark_last_busy(dd
->dev
);
39 pm_runtime_put_autosuspend(dd
->dev
);
42 static void omap_aes_gcm_done_task(struct omap_aes_dev
*dd
)
45 int alen
, clen
, i
, ret
= 0, nsg
;
46 struct omap_aes_reqctx
*rctx
;
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
);
52 nsg
= !!(dd
->assoc_len
&& dd
->total
);
54 dma_sync_sg_for_device(dd
->dev
, dd
->out_sg
, dd
->out_sg_len
,
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
);
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
);
64 if (dd
->flags
& FLAGS_ENCRYPT
)
65 scatterwalk_map_and_copy(rctx
->auth_tag
,
67 dd
->total
+ dd
->aead_req
->assoclen
,
70 omap_crypto_cleanup(&dd
->in_sgl
[0], NULL
, 0, alen
,
71 FLAGS_ASSOC_DATA_ST_SHIFT
, dd
->flags
);
73 omap_crypto_cleanup(&dd
->in_sgl
[nsg
], NULL
, 0, clen
,
74 FLAGS_IN_DATA_ST_SHIFT
, dd
->flags
);
76 if (!(dd
->flags
& FLAGS_ENCRYPT
)) {
77 tag
= (u8
*)rctx
->auth_tag
;
78 for (i
= 0; i
< dd
->authsize
; i
++) {
85 omap_aes_gcm_finish_req(dd
, ret
);
88 static int omap_aes_gcm_copy_buffers(struct omap_aes_dev
*dd
,
89 struct aead_request
*req
)
91 int alen
, clen
, cryptlen
, assoclen
, ret
;
92 struct crypto_aead
*aead
= crypto_aead_reqtfm(req
);
93 unsigned int authlen
= crypto_aead_authsize(aead
);
94 struct scatterlist
*tmp
, sg_arr
[2];
98 assoclen
= req
->assoclen
;
99 cryptlen
= req
->cryptlen
;
101 if (dd
->flags
& FLAGS_RFC4106_GCM
)
104 if (!(dd
->flags
& FLAGS_ENCRYPT
))
107 alen
= ALIGN(assoclen
, AES_BLOCK_SIZE
);
108 clen
= ALIGN(cryptlen
, AES_BLOCK_SIZE
);
110 nsg
= !!(assoclen
&& cryptlen
);
112 omap_aes_clear_copy_flags(dd
);
114 sg_init_table(dd
->in_sgl
, nsg
+ 1);
117 ret
= omap_crypto_align_sg(&tmp
, assoclen
,
118 AES_BLOCK_SIZE
, dd
->in_sgl
,
119 OMAP_CRYPTO_COPY_DATA
|
120 OMAP_CRYPTO_ZERO_BUF
|
121 OMAP_CRYPTO_FORCE_SINGLE_ENTRY
,
122 FLAGS_ASSOC_DATA_ST_SHIFT
,
129 tmp
= scatterwalk_ffwd(sg_arr
, req
->src
, req
->assoclen
);
132 sg_unmark_end(dd
->in_sgl
);
134 ret
= omap_crypto_align_sg(&tmp
, cryptlen
,
135 AES_BLOCK_SIZE
, &dd
->in_sgl
[nsg
],
136 OMAP_CRYPTO_COPY_DATA
|
137 OMAP_CRYPTO_ZERO_BUF
|
138 OMAP_CRYPTO_FORCE_SINGLE_ENTRY
,
139 FLAGS_IN_DATA_ST_SHIFT
,
145 dd
->in_sg
= dd
->in_sgl
;
146 dd
->total
= cryptlen
;
147 dd
->assoc_len
= assoclen
;
148 dd
->authsize
= authlen
;
150 dd
->out_sg
= req
->dst
;
151 dd
->orig_out
= req
->dst
;
153 dd
->out_sg
= scatterwalk_ffwd(sg_arr
, req
->dst
, req
->assoclen
);
156 if (req
->src
== req
->dst
|| dd
->out_sg
== sg_arr
)
157 flags
|= OMAP_CRYPTO_FORCE_COPY
;
160 ret
= omap_crypto_align_sg(&dd
->out_sg
, cryptlen
,
161 AES_BLOCK_SIZE
, &dd
->out_sgl
,
163 FLAGS_OUT_DATA_ST_SHIFT
, &dd
->flags
);
168 dd
->in_sg_len
= sg_nents_for_len(dd
->in_sg
, alen
+ clen
);
169 dd
->out_sg_len
= sg_nents_for_len(dd
->out_sg
, clen
);
174 static int do_encrypt_iv(struct aead_request
*req
, u32
*tag
, u32
*iv
)
176 struct omap_aes_gcm_ctx
*ctx
= crypto_aead_ctx(crypto_aead_reqtfm(req
));
178 aes_encrypt(&ctx
->actx
, (u8
*)tag
, (u8
*)iv
);
182 void omap_aes_gcm_dma_out_callback(void *data
)
184 struct omap_aes_dev
*dd
= data
;
185 struct omap_aes_reqctx
*rctx
;
187 u32
*auth_tag
, tag
[4];
189 if (!(dd
->flags
& FLAGS_ENCRYPT
))
190 scatterwalk_map_and_copy(tag
, dd
->aead_req
->src
,
191 dd
->total
+ dd
->aead_req
->assoclen
,
194 rctx
= aead_request_ctx(dd
->aead_req
);
195 auth_tag
= (u32
*)rctx
->auth_tag
;
196 for (i
= 0; i
< 4; i
++) {
197 val
= omap_aes_read(dd
, AES_REG_TAG_N(dd
, i
));
198 auth_tag
[i
] = val
^ auth_tag
[i
];
199 if (!(dd
->flags
& FLAGS_ENCRYPT
))
200 auth_tag
[i
] = auth_tag
[i
] ^ tag
[i
];
203 omap_aes_gcm_done_task(dd
);
206 static int omap_aes_gcm_handle_queue(struct omap_aes_dev
*dd
,
207 struct aead_request
*req
)
210 return crypto_transfer_aead_request_to_engine(dd
->engine
, req
);
215 static int omap_aes_gcm_prepare_req(struct crypto_engine
*engine
, void *areq
)
217 struct aead_request
*req
= container_of(areq
, struct aead_request
,
219 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
220 struct omap_aes_dev
*dd
= rctx
->dd
;
221 struct omap_aes_gcm_ctx
*ctx
= crypto_aead_ctx(crypto_aead_reqtfm(req
));
226 rctx
->mode
&= FLAGS_MODE_MASK
;
227 dd
->flags
= (dd
->flags
& ~FLAGS_MODE_MASK
) | rctx
->mode
;
229 err
= omap_aes_gcm_copy_buffers(dd
, req
);
233 dd
->ctx
= &ctx
->octx
;
235 return omap_aes_write_ctrl(dd
);
238 static int omap_aes_gcm_crypt(struct aead_request
*req
, unsigned long mode
)
240 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
241 struct crypto_aead
*aead
= crypto_aead_reqtfm(req
);
242 unsigned int authlen
= crypto_aead_authsize(aead
);
243 struct omap_aes_dev
*dd
;
244 __be32 counter
= cpu_to_be32(1);
247 memset(rctx
->auth_tag
, 0, sizeof(rctx
->auth_tag
));
248 memcpy(rctx
->iv
+ GCM_AES_IV_SIZE
, &counter
, 4);
250 err
= do_encrypt_iv(req
, (u32
*)rctx
->auth_tag
, (u32
*)rctx
->iv
);
254 if (mode
& FLAGS_RFC4106_GCM
)
255 assoclen
= req
->assoclen
- 8;
257 assoclen
= req
->assoclen
;
258 if (assoclen
+ req
->cryptlen
== 0) {
259 scatterwalk_map_and_copy(rctx
->auth_tag
, req
->dst
, 0, authlen
,
264 dd
= omap_aes_find_dev(rctx
);
269 return omap_aes_gcm_handle_queue(dd
, req
);
272 int omap_aes_gcm_encrypt(struct aead_request
*req
)
274 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
276 memcpy(rctx
->iv
, req
->iv
, GCM_AES_IV_SIZE
);
277 return omap_aes_gcm_crypt(req
, FLAGS_ENCRYPT
| FLAGS_GCM
);
280 int omap_aes_gcm_decrypt(struct aead_request
*req
)
282 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
284 memcpy(rctx
->iv
, req
->iv
, GCM_AES_IV_SIZE
);
285 return omap_aes_gcm_crypt(req
, FLAGS_GCM
);
288 int omap_aes_4106gcm_encrypt(struct aead_request
*req
)
290 struct omap_aes_gcm_ctx
*ctx
= crypto_aead_ctx(crypto_aead_reqtfm(req
));
291 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
293 memcpy(rctx
->iv
, ctx
->octx
.nonce
, 4);
294 memcpy(rctx
->iv
+ 4, req
->iv
, 8);
295 return crypto_ipsec_check_assoclen(req
->assoclen
) ?:
296 omap_aes_gcm_crypt(req
, FLAGS_ENCRYPT
| FLAGS_GCM
|
300 int omap_aes_4106gcm_decrypt(struct aead_request
*req
)
302 struct omap_aes_gcm_ctx
*ctx
= crypto_aead_ctx(crypto_aead_reqtfm(req
));
303 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
305 memcpy(rctx
->iv
, ctx
->octx
.nonce
, 4);
306 memcpy(rctx
->iv
+ 4, req
->iv
, 8);
307 return crypto_ipsec_check_assoclen(req
->assoclen
) ?:
308 omap_aes_gcm_crypt(req
, FLAGS_GCM
| FLAGS_RFC4106_GCM
);
311 int omap_aes_gcm_setkey(struct crypto_aead
*tfm
, const u8
*key
,
314 struct omap_aes_gcm_ctx
*ctx
= crypto_aead_ctx(tfm
);
317 ret
= aes_expandkey(&ctx
->actx
, key
, keylen
);
321 memcpy(ctx
->octx
.key
, key
, keylen
);
322 ctx
->octx
.keylen
= keylen
;
327 int omap_aes_4106gcm_setkey(struct crypto_aead
*tfm
, const u8
*key
,
330 struct omap_aes_gcm_ctx
*ctx
= crypto_aead_ctx(tfm
);
337 ret
= aes_expandkey(&ctx
->actx
, key
, keylen
);
341 memcpy(ctx
->octx
.key
, key
, keylen
);
342 memcpy(ctx
->octx
.nonce
, key
+ keylen
, 4);
343 ctx
->octx
.keylen
= keylen
;
348 int omap_aes_gcm_setauthsize(struct crypto_aead
*tfm
, unsigned int authsize
)
350 return crypto_gcm_check_authsize(authsize
);
353 int omap_aes_4106gcm_setauthsize(struct crypto_aead
*parent
,
354 unsigned int authsize
)
356 return crypto_rfc4106_check_authsize(authsize
);
359 static int omap_aes_gcm_crypt_req(struct crypto_engine
*engine
, void *areq
)
361 struct aead_request
*req
= container_of(areq
, struct aead_request
,
363 struct omap_aes_reqctx
*rctx
= aead_request_ctx(req
);
364 struct omap_aes_dev
*dd
= rctx
->dd
;
371 ret
= omap_aes_crypt_dma_start(dd
);
373 omap_aes_gcm_dma_out_callback(dd
);
378 int omap_aes_gcm_cra_init(struct crypto_aead
*tfm
)
380 struct omap_aes_ctx
*ctx
= crypto_aead_ctx(tfm
);
382 ctx
->enginectx
.op
.prepare_request
= omap_aes_gcm_prepare_req
;
383 ctx
->enginectx
.op
.unprepare_request
= NULL
;
384 ctx
->enginectx
.op
.do_one_request
= omap_aes_gcm_crypt_req
;
386 crypto_aead_set_reqsize(tfm
, sizeof(struct omap_aes_reqctx
));