Commit | Line | Data |
---|---|---|
06f751b6 CL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * sun8i-ce-cipher.c - hardware cryptographic offloader for | |
4 | * Allwinner H3/A64/H5/H2+/H6/R40 SoC | |
5 | * | |
6 | * Copyright (C) 2016-2019 Corentin LABBE <clabbe.montjoie@gmail.com> | |
7 | * | |
8 | * This file add support for AES cipher with 128,192,256 bits keysize in | |
9 | * CBC and ECB mode. | |
10 | * | |
39db3f15 | 11 | * You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst |
06f751b6 CL |
12 | */ |
13 | ||
f75a749b | 14 | #include <linux/bottom_half.h> |
06f751b6 CL |
15 | #include <linux/crypto.h> |
16 | #include <linux/dma-mapping.h> | |
17 | #include <linux/io.h> | |
18 | #include <linux/pm_runtime.h> | |
19 | #include <crypto/scatterwalk.h> | |
20 | #include <crypto/internal/des.h> | |
21 | #include <crypto/internal/skcipher.h> | |
22 | #include "sun8i-ce.h" | |
23 | ||
24 | static int sun8i_ce_cipher_need_fallback(struct skcipher_request *areq) | |
25 | { | |
26 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); | |
27 | struct scatterlist *sg; | |
aff388f7 CL |
28 | struct skcipher_alg *alg = crypto_skcipher_alg(tfm); |
29 | struct sun8i_ce_alg_template *algt; | |
42a01af3 | 30 | unsigned int todo, len; |
aff388f7 | 31 | |
07e34cd3 | 32 | algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base); |
06f751b6 | 33 | |
6b8309fa | 34 | if (sg_nents_for_len(areq->src, areq->cryptlen) > MAX_SG || |
aff388f7 CL |
35 | sg_nents_for_len(areq->dst, areq->cryptlen) > MAX_SG) { |
36 | algt->stat_fb_maxsg++; | |
06f751b6 | 37 | return true; |
aff388f7 CL |
38 | } |
39 | ||
40 | if (areq->cryptlen < crypto_skcipher_ivsize(tfm)) { | |
41 | algt->stat_fb_leniv++; | |
42 | return true; | |
43 | } | |
06f751b6 | 44 | |
aff388f7 CL |
45 | if (areq->cryptlen == 0) { |
46 | algt->stat_fb_len0++; | |
06f751b6 | 47 | return true; |
aff388f7 | 48 | } |
06f751b6 | 49 | |
aff388f7 CL |
50 | if (areq->cryptlen % 16) { |
51 | algt->stat_fb_mod16++; | |
06f751b6 | 52 | return true; |
aff388f7 | 53 | } |
06f751b6 | 54 | |
42a01af3 | 55 | len = areq->cryptlen; |
06f751b6 CL |
56 | sg = areq->src; |
57 | while (sg) { | |
aff388f7 CL |
58 | if (!IS_ALIGNED(sg->offset, sizeof(u32))) { |
59 | algt->stat_fb_srcali++; | |
60 | return true; | |
61 | } | |
42a01af3 CL |
62 | todo = min(len, sg->length); |
63 | if (todo % 4) { | |
aff388f7 | 64 | algt->stat_fb_srclen++; |
06f751b6 | 65 | return true; |
aff388f7 | 66 | } |
42a01af3 | 67 | len -= todo; |
06f751b6 CL |
68 | sg = sg_next(sg); |
69 | } | |
42a01af3 CL |
70 | |
71 | len = areq->cryptlen; | |
06f751b6 CL |
72 | sg = areq->dst; |
73 | while (sg) { | |
aff388f7 CL |
74 | if (!IS_ALIGNED(sg->offset, sizeof(u32))) { |
75 | algt->stat_fb_dstali++; | |
76 | return true; | |
77 | } | |
42a01af3 CL |
78 | todo = min(len, sg->length); |
79 | if (todo % 4) { | |
aff388f7 | 80 | algt->stat_fb_dstlen++; |
06f751b6 | 81 | return true; |
aff388f7 | 82 | } |
42a01af3 | 83 | len -= todo; |
06f751b6 CL |
84 | sg = sg_next(sg); |
85 | } | |
86 | return false; | |
87 | } | |
88 | ||
89 | static int sun8i_ce_cipher_fallback(struct skcipher_request *areq) | |
90 | { | |
91 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); | |
92 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
93 | struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); | |
94 | int err; | |
06f751b6 | 95 | |
07e34cd3 HX |
96 | if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { |
97 | struct skcipher_alg *alg = crypto_skcipher_alg(tfm); | |
98 | struct sun8i_ce_alg_template *algt __maybe_unused; | |
99 | ||
100 | algt = container_of(alg, struct sun8i_ce_alg_template, | |
101 | alg.skcipher.base); | |
102 | ||
103 | #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG | |
104 | algt->stat_fb++; | |
06f751b6 | 105 | #endif |
07e34cd3 | 106 | } |
06f751b6 | 107 | |
31abd3eb AB |
108 | skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm); |
109 | skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags, | |
110 | areq->base.complete, areq->base.data); | |
111 | skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst, | |
06f751b6 CL |
112 | areq->cryptlen, areq->iv); |
113 | if (rctx->op_dir & CE_DECRYPTION) | |
31abd3eb | 114 | err = crypto_skcipher_decrypt(&rctx->fallback_req); |
06f751b6 | 115 | else |
31abd3eb | 116 | err = crypto_skcipher_encrypt(&rctx->fallback_req); |
06f751b6 CL |
117 | return err; |
118 | } | |
119 | ||
0605fa0f | 120 | static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req) |
06f751b6 | 121 | { |
0605fa0f | 122 | struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base); |
06f751b6 CL |
123 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); |
124 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
125 | struct sun8i_ce_dev *ce = op->ce; | |
126 | struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); | |
127 | struct skcipher_alg *alg = crypto_skcipher_alg(tfm); | |
128 | struct sun8i_ce_alg_template *algt; | |
129 | struct sun8i_ce_flow *chan; | |
130 | struct ce_task *cet; | |
131 | struct scatterlist *sg; | |
132 | unsigned int todo, len, offset, ivsize; | |
93c7f4d3 | 133 | u32 common, sym; |
06f751b6 CL |
134 | int flow, i; |
135 | int nr_sgs = 0; | |
136 | int nr_sgd = 0; | |
137 | int err = 0; | |
6b8309fa CL |
138 | int ns = sg_nents_for_len(areq->src, areq->cryptlen); |
139 | int nd = sg_nents_for_len(areq->dst, areq->cryptlen); | |
06f751b6 | 140 | |
07e34cd3 | 141 | algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base); |
06f751b6 CL |
142 | |
143 | dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__, | |
144 | crypto_tfm_alg_name(areq->base.tfm), | |
145 | areq->cryptlen, | |
146 | rctx->op_dir, areq->iv, crypto_skcipher_ivsize(tfm), | |
147 | op->keylen); | |
148 | ||
149 | #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG | |
150 | algt->stat_req++; | |
151 | #endif | |
152 | ||
153 | flow = rctx->flow; | |
154 | ||
155 | chan = &ce->chanlist[flow]; | |
156 | ||
157 | cet = chan->tl; | |
158 | memset(cet, 0, sizeof(struct ce_task)); | |
159 | ||
93c7f4d3 CL |
160 | cet->t_id = cpu_to_le32(flow); |
161 | common = ce->variant->alg_cipher[algt->ce_algo_id]; | |
162 | common |= rctx->op_dir | CE_COMM_INT; | |
163 | cet->t_common_ctl = cpu_to_le32(common); | |
06f751b6 | 164 | /* CTS and recent CE (H6) need length in bytes, in word otherwise */ |
6b4f76c2 | 165 | if (ce->variant->cipher_t_dlen_in_bytes) |
93c7f4d3 CL |
166 | cet->t_dlen = cpu_to_le32(areq->cryptlen); |
167 | else | |
168 | cet->t_dlen = cpu_to_le32(areq->cryptlen / 4); | |
06f751b6 | 169 | |
93c7f4d3 | 170 | sym = ce->variant->op_mode[algt->ce_blockmode]; |
06f751b6 CL |
171 | len = op->keylen; |
172 | switch (len) { | |
173 | case 128 / 8: | |
93c7f4d3 | 174 | sym |= CE_AES_128BITS; |
06f751b6 CL |
175 | break; |
176 | case 192 / 8: | |
93c7f4d3 | 177 | sym |= CE_AES_192BITS; |
06f751b6 CL |
178 | break; |
179 | case 256 / 8: | |
93c7f4d3 | 180 | sym |= CE_AES_256BITS; |
06f751b6 CL |
181 | break; |
182 | } | |
183 | ||
93c7f4d3 | 184 | cet->t_sym_ctl = cpu_to_le32(sym); |
06f751b6 CL |
185 | cet->t_asym_ctl = 0; |
186 | ||
0605fa0f CL |
187 | rctx->addr_key = dma_map_single(ce->dev, op->key, op->keylen, DMA_TO_DEVICE); |
188 | if (dma_mapping_error(ce->dev, rctx->addr_key)) { | |
06f751b6 CL |
189 | dev_err(ce->dev, "Cannot DMA MAP KEY\n"); |
190 | err = -EFAULT; | |
191 | goto theend; | |
192 | } | |
0605fa0f | 193 | cet->t_key = cpu_to_le32(rctx->addr_key); |
06f751b6 CL |
194 | |
195 | ivsize = crypto_skcipher_ivsize(tfm); | |
196 | if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) { | |
a216f8d5 | 197 | rctx->ivlen = ivsize; |
06f751b6 | 198 | if (rctx->op_dir & CE_DECRYPTION) { |
06f751b6 | 199 | offset = areq->cryptlen - ivsize; |
22f7c2f8 | 200 | scatterwalk_map_and_copy(chan->backup_iv, areq->src, |
a216f8d5 | 201 | offset, ivsize, 0); |
06f751b6 | 202 | } |
22f7c2f8 CL |
203 | memcpy(chan->bounce_iv, areq->iv, ivsize); |
204 | rctx->addr_iv = dma_map_single(ce->dev, chan->bounce_iv, rctx->ivlen, | |
0605fa0f CL |
205 | DMA_TO_DEVICE); |
206 | if (dma_mapping_error(ce->dev, rctx->addr_iv)) { | |
06f751b6 CL |
207 | dev_err(ce->dev, "Cannot DMA MAP IV\n"); |
208 | err = -ENOMEM; | |
209 | goto theend_iv; | |
210 | } | |
0605fa0f | 211 | cet->t_iv = cpu_to_le32(rctx->addr_iv); |
06f751b6 CL |
212 | } |
213 | ||
214 | if (areq->src == areq->dst) { | |
6b8309fa | 215 | nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_BIDIRECTIONAL); |
06f751b6 CL |
216 | if (nr_sgs <= 0 || nr_sgs > MAX_SG) { |
217 | dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs); | |
218 | err = -EINVAL; | |
219 | goto theend_iv; | |
220 | } | |
221 | nr_sgd = nr_sgs; | |
222 | } else { | |
6b8309fa | 223 | nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE); |
06f751b6 CL |
224 | if (nr_sgs <= 0 || nr_sgs > MAX_SG) { |
225 | dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs); | |
226 | err = -EINVAL; | |
227 | goto theend_iv; | |
228 | } | |
6b8309fa | 229 | nr_sgd = dma_map_sg(ce->dev, areq->dst, nd, DMA_FROM_DEVICE); |
06f751b6 CL |
230 | if (nr_sgd <= 0 || nr_sgd > MAX_SG) { |
231 | dev_err(ce->dev, "Invalid sg number %d\n", nr_sgd); | |
232 | err = -EINVAL; | |
233 | goto theend_sgs; | |
234 | } | |
235 | } | |
236 | ||
237 | len = areq->cryptlen; | |
238 | for_each_sg(areq->src, sg, nr_sgs, i) { | |
93c7f4d3 | 239 | cet->t_src[i].addr = cpu_to_le32(sg_dma_address(sg)); |
06f751b6 | 240 | todo = min(len, sg_dma_len(sg)); |
93c7f4d3 | 241 | cet->t_src[i].len = cpu_to_le32(todo / 4); |
06f751b6 CL |
242 | dev_dbg(ce->dev, "%s total=%u SG(%d %u off=%d) todo=%u\n", __func__, |
243 | areq->cryptlen, i, cet->t_src[i].len, sg->offset, todo); | |
244 | len -= todo; | |
245 | } | |
246 | if (len > 0) { | |
247 | dev_err(ce->dev, "remaining len %d\n", len); | |
248 | err = -EINVAL; | |
249 | goto theend_sgs; | |
250 | } | |
251 | ||
252 | len = areq->cryptlen; | |
253 | for_each_sg(areq->dst, sg, nr_sgd, i) { | |
93c7f4d3 | 254 | cet->t_dst[i].addr = cpu_to_le32(sg_dma_address(sg)); |
06f751b6 | 255 | todo = min(len, sg_dma_len(sg)); |
93c7f4d3 | 256 | cet->t_dst[i].len = cpu_to_le32(todo / 4); |
06f751b6 CL |
257 | dev_dbg(ce->dev, "%s total=%u SG(%d %u off=%d) todo=%u\n", __func__, |
258 | areq->cryptlen, i, cet->t_dst[i].len, sg->offset, todo); | |
259 | len -= todo; | |
260 | } | |
261 | if (len > 0) { | |
262 | dev_err(ce->dev, "remaining len %d\n", len); | |
263 | err = -EINVAL; | |
264 | goto theend_sgs; | |
265 | } | |
266 | ||
267 | chan->timeout = areq->cryptlen; | |
0605fa0f CL |
268 | rctx->nr_sgs = nr_sgs; |
269 | rctx->nr_sgd = nr_sgd; | |
270 | return 0; | |
06f751b6 CL |
271 | |
272 | theend_sgs: | |
273 | if (areq->src == areq->dst) { | |
6b8309fa | 274 | dma_unmap_sg(ce->dev, areq->src, ns, DMA_BIDIRECTIONAL); |
06f751b6 CL |
275 | } else { |
276 | if (nr_sgs > 0) | |
6b8309fa CL |
277 | dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE); |
278 | dma_unmap_sg(ce->dev, areq->dst, nd, DMA_FROM_DEVICE); | |
06f751b6 CL |
279 | } |
280 | ||
281 | theend_iv: | |
282 | if (areq->iv && ivsize > 0) { | |
0605fa0f CL |
283 | if (rctx->addr_iv) |
284 | dma_unmap_single(ce->dev, rctx->addr_iv, rctx->ivlen, DMA_TO_DEVICE); | |
06f751b6 CL |
285 | offset = areq->cryptlen - ivsize; |
286 | if (rctx->op_dir & CE_DECRYPTION) { | |
22f7c2f8 CL |
287 | memcpy(areq->iv, chan->backup_iv, ivsize); |
288 | memzero_explicit(chan->backup_iv, ivsize); | |
06f751b6 CL |
289 | } else { |
290 | scatterwalk_map_and_copy(areq->iv, areq->dst, offset, | |
291 | ivsize, 0); | |
292 | } | |
22f7c2f8 | 293 | memzero_explicit(chan->bounce_iv, ivsize); |
06f751b6 CL |
294 | } |
295 | ||
0605fa0f | 296 | dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE); |
06f751b6 CL |
297 | |
298 | theend: | |
299 | return err; | |
300 | } | |
301 | ||
4136212a HX |
302 | static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine, |
303 | void *async_req) | |
0605fa0f CL |
304 | { |
305 | struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base); | |
306 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); | |
307 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
308 | struct sun8i_ce_dev *ce = op->ce; | |
309 | struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); | |
310 | struct sun8i_ce_flow *chan; | |
311 | struct ce_task *cet; | |
312 | unsigned int ivsize, offset; | |
313 | int nr_sgs = rctx->nr_sgs; | |
314 | int nr_sgd = rctx->nr_sgd; | |
315 | int flow; | |
316 | ||
317 | flow = rctx->flow; | |
318 | chan = &ce->chanlist[flow]; | |
319 | cet = chan->tl; | |
320 | ivsize = crypto_skcipher_ivsize(tfm); | |
321 | ||
322 | if (areq->src == areq->dst) { | |
323 | dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL); | |
324 | } else { | |
325 | if (nr_sgs > 0) | |
326 | dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_TO_DEVICE); | |
327 | dma_unmap_sg(ce->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE); | |
328 | } | |
329 | ||
330 | if (areq->iv && ivsize > 0) { | |
331 | if (cet->t_iv) | |
332 | dma_unmap_single(ce->dev, rctx->addr_iv, rctx->ivlen, DMA_TO_DEVICE); | |
333 | offset = areq->cryptlen - ivsize; | |
334 | if (rctx->op_dir & CE_DECRYPTION) { | |
22f7c2f8 CL |
335 | memcpy(areq->iv, chan->backup_iv, ivsize); |
336 | memzero_explicit(chan->backup_iv, ivsize); | |
0605fa0f CL |
337 | } else { |
338 | scatterwalk_map_and_copy(areq->iv, areq->dst, offset, | |
339 | ivsize, 0); | |
340 | } | |
22f7c2f8 | 341 | memzero_explicit(chan->bounce_iv, ivsize); |
0605fa0f CL |
342 | } |
343 | ||
344 | dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE); | |
4136212a HX |
345 | } |
346 | ||
18342003 AS |
347 | static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq) |
348 | { | |
349 | struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); | |
350 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq); | |
351 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
352 | struct sun8i_ce_dev *ce = op->ce; | |
353 | struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq); | |
354 | int flow, err; | |
355 | ||
356 | flow = rctx->flow; | |
357 | err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); | |
358 | sun8i_ce_cipher_unprepare(engine, areq); | |
359 | local_bh_disable(); | |
360 | crypto_finalize_skcipher_request(engine, breq, err); | |
361 | local_bh_enable(); | |
362 | } | |
363 | ||
07e34cd3 | 364 | int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq) |
4136212a HX |
365 | { |
366 | int err = sun8i_ce_cipher_prepare(engine, areq); | |
367 | ||
368 | if (err) | |
369 | return err; | |
06f751b6 | 370 | |
4136212a | 371 | sun8i_ce_cipher_run(engine, areq); |
06f751b6 CL |
372 | return 0; |
373 | } | |
374 | ||
375 | int sun8i_ce_skdecrypt(struct skcipher_request *areq) | |
376 | { | |
377 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); | |
378 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
379 | struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); | |
380 | struct crypto_engine *engine; | |
381 | int e; | |
382 | ||
383 | rctx->op_dir = CE_DECRYPTION; | |
384 | if (sun8i_ce_cipher_need_fallback(areq)) | |
385 | return sun8i_ce_cipher_fallback(areq); | |
386 | ||
387 | e = sun8i_ce_get_engine_number(op->ce); | |
388 | rctx->flow = e; | |
389 | engine = op->ce->chanlist[e].engine; | |
390 | ||
391 | return crypto_transfer_skcipher_request_to_engine(engine, areq); | |
392 | } | |
393 | ||
394 | int sun8i_ce_skencrypt(struct skcipher_request *areq) | |
395 | { | |
396 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); | |
397 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
398 | struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); | |
399 | struct crypto_engine *engine; | |
400 | int e; | |
401 | ||
402 | rctx->op_dir = CE_ENCRYPTION; | |
403 | if (sun8i_ce_cipher_need_fallback(areq)) | |
404 | return sun8i_ce_cipher_fallback(areq); | |
405 | ||
406 | e = sun8i_ce_get_engine_number(op->ce); | |
407 | rctx->flow = e; | |
408 | engine = op->ce->chanlist[e].engine; | |
409 | ||
410 | return crypto_transfer_skcipher_request_to_engine(engine, areq); | |
411 | } | |
412 | ||
413 | int sun8i_ce_cipher_init(struct crypto_tfm *tfm) | |
414 | { | |
415 | struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm); | |
416 | struct sun8i_ce_alg_template *algt; | |
417 | const char *name = crypto_tfm_alg_name(tfm); | |
418 | struct crypto_skcipher *sktfm = __crypto_skcipher_cast(tfm); | |
419 | struct skcipher_alg *alg = crypto_skcipher_alg(sktfm); | |
420 | int err; | |
421 | ||
422 | memset(op, 0, sizeof(struct sun8i_cipher_tfm_ctx)); | |
423 | ||
07e34cd3 | 424 | algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base); |
06f751b6 CL |
425 | op->ce = algt->ce; |
426 | ||
31abd3eb | 427 | op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); |
06f751b6 CL |
428 | if (IS_ERR(op->fallback_tfm)) { |
429 | dev_err(op->ce->dev, "ERROR: Cannot allocate fallback for %s %ld\n", | |
430 | name, PTR_ERR(op->fallback_tfm)); | |
431 | return PTR_ERR(op->fallback_tfm); | |
432 | } | |
433 | ||
e9b21862 OP |
434 | crypto_skcipher_set_reqsize(sktfm, sizeof(struct sun8i_cipher_req_ctx) + |
435 | crypto_skcipher_reqsize(op->fallback_tfm)); | |
31abd3eb | 436 | |
aff388f7 CL |
437 | memcpy(algt->fbname, |
438 | crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)), | |
439 | CRYPTO_MAX_ALG_NAME); | |
06f751b6 | 440 | |
06f751b6 CL |
441 | err = pm_runtime_get_sync(op->ce->dev); |
442 | if (err < 0) | |
443 | goto error_pm; | |
444 | ||
445 | return 0; | |
446 | error_pm: | |
5c3a8a66 | 447 | pm_runtime_put_noidle(op->ce->dev); |
31abd3eb | 448 | crypto_free_skcipher(op->fallback_tfm); |
06f751b6 CL |
449 | return err; |
450 | } | |
451 | ||
452 | void sun8i_ce_cipher_exit(struct crypto_tfm *tfm) | |
453 | { | |
454 | struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm); | |
455 | ||
712d8069 | 456 | kfree_sensitive(op->key); |
31abd3eb | 457 | crypto_free_skcipher(op->fallback_tfm); |
06f751b6 CL |
458 | pm_runtime_put_sync_suspend(op->ce->dev); |
459 | } | |
460 | ||
461 | int sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, | |
462 | unsigned int keylen) | |
463 | { | |
464 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
465 | struct sun8i_ce_dev *ce = op->ce; | |
466 | ||
467 | switch (keylen) { | |
468 | case 128 / 8: | |
469 | break; | |
470 | case 192 / 8: | |
471 | break; | |
472 | case 256 / 8: | |
473 | break; | |
474 | default: | |
475 | dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen); | |
06f751b6 CL |
476 | return -EINVAL; |
477 | } | |
712d8069 | 478 | kfree_sensitive(op->key); |
06f751b6 | 479 | op->keylen = keylen; |
c7351845 | 480 | op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA); |
06f751b6 CL |
481 | if (!op->key) |
482 | return -ENOMEM; | |
06f751b6 | 483 | |
31abd3eb AB |
484 | crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); |
485 | crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); | |
06f751b6 | 486 | |
31abd3eb | 487 | return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); |
06f751b6 CL |
488 | } |
489 | ||
490 | int sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, | |
491 | unsigned int keylen) | |
492 | { | |
493 | struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); | |
494 | int err; | |
495 | ||
496 | err = verify_skcipher_des3_key(tfm, key); | |
497 | if (err) | |
498 | return err; | |
499 | ||
712d8069 | 500 | kfree_sensitive(op->key); |
06f751b6 | 501 | op->keylen = keylen; |
c7351845 | 502 | op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA); |
06f751b6 CL |
503 | if (!op->key) |
504 | return -ENOMEM; | |
06f751b6 | 505 | |
31abd3eb AB |
506 | crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); |
507 | crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); | |
06f751b6 | 508 | |
31abd3eb | 509 | return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); |
06f751b6 | 510 | } |