Commit | Line | Data |
---|---|---|
85a7f0ac SAS |
1 | /* |
2 | * Support for Marvell's crypto engine which can be found on some Orion5X | |
3 | * boards. | |
4 | * | |
5 | * Author: Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > | |
6 | * License: GPLv2 | |
7 | * | |
8 | */ | |
9 | #include <crypto/aes.h> | |
10 | #include <crypto/algapi.h> | |
11 | #include <linux/crypto.h> | |
12 | #include <linux/interrupt.h> | |
13 | #include <linux/io.h> | |
14 | #include <linux/kthread.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/scatterlist.h> | |
17 | ||
18 | #include "mv_cesa.h" | |
19 | /* | |
20 | * STM: | |
21 | * /---------------------------------------\ | |
22 | * | | request complete | |
23 | * \./ | | |
24 | * IDLE -> new request -> BUSY -> done -> DEQUEUE | |
25 | * /°\ | | |
26 | * | | more scatter entries | |
27 | * \________________/ | |
28 | */ | |
29 | enum engine_status { | |
30 | ENGINE_IDLE, | |
31 | ENGINE_BUSY, | |
32 | ENGINE_W_DEQUEUE, | |
33 | }; | |
34 | ||
35 | /** | |
36 | * struct req_progress - used for every crypt request | |
37 | * @src_sg_it: sg iterator for src | |
38 | * @dst_sg_it: sg iterator for dst | |
39 | * @sg_src_left: bytes left in src to process (scatter list) | |
40 | * @src_start: offset to add to src start position (scatter list) | |
41 | * @crypt_len: length of current crypt process | |
3b61a905 | 42 | * @hw_nbytes: total bytes to process in hw for this request |
85a7f0ac SAS |
43 | * @sg_dst_left: bytes left dst to process in this scatter list |
44 | * @dst_start: offset to add to dst start position (scatter list) | |
7a5f691e | 45 | * @hw_processed_bytes: number of bytes processed by hw (request). |
85a7f0ac SAS |
46 | * |
47 | * sg helper are used to iterate over the scatterlist. Since the size of the | |
48 | * SRAM may be less than the scatter size, this struct struct is used to keep | |
49 | * track of progress within current scatterlist. | |
50 | */ | |
51 | struct req_progress { | |
52 | struct sg_mapping_iter src_sg_it; | |
53 | struct sg_mapping_iter dst_sg_it; | |
54 | ||
55 | /* src mostly */ | |
56 | int sg_src_left; | |
57 | int src_start; | |
58 | int crypt_len; | |
3b61a905 | 59 | int hw_nbytes; |
85a7f0ac SAS |
60 | /* dst mostly */ |
61 | int sg_dst_left; | |
62 | int dst_start; | |
7a5f691e | 63 | int hw_processed_bytes; |
85a7f0ac SAS |
64 | }; |
65 | ||
66 | struct crypto_priv { | |
67 | void __iomem *reg; | |
68 | void __iomem *sram; | |
69 | int irq; | |
70 | struct task_struct *queue_th; | |
71 | ||
72 | /* the lock protects queue and eng_st */ | |
73 | spinlock_t lock; | |
74 | struct crypto_queue queue; | |
75 | enum engine_status eng_st; | |
3b61a905 | 76 | struct crypto_async_request *cur_req; |
85a7f0ac SAS |
77 | struct req_progress p; |
78 | int max_req_size; | |
79 | int sram_size; | |
80 | }; | |
81 | ||
82 | static struct crypto_priv *cpg; | |
83 | ||
84 | struct mv_ctx { | |
85 | u8 aes_enc_key[AES_KEY_LEN]; | |
86 | u32 aes_dec_key[8]; | |
87 | int key_len; | |
88 | u32 need_calc_aes_dkey; | |
89 | }; | |
90 | ||
91 | enum crypto_op { | |
92 | COP_AES_ECB, | |
93 | COP_AES_CBC, | |
94 | }; | |
95 | ||
96 | struct mv_req_ctx { | |
97 | enum crypto_op op; | |
98 | int decrypt; | |
99 | }; | |
100 | ||
101 | static void compute_aes_dec_key(struct mv_ctx *ctx) | |
102 | { | |
103 | struct crypto_aes_ctx gen_aes_key; | |
104 | int key_pos; | |
105 | ||
106 | if (!ctx->need_calc_aes_dkey) | |
107 | return; | |
108 | ||
109 | crypto_aes_expand_key(&gen_aes_key, ctx->aes_enc_key, ctx->key_len); | |
110 | ||
111 | key_pos = ctx->key_len + 24; | |
112 | memcpy(ctx->aes_dec_key, &gen_aes_key.key_enc[key_pos], 4 * 4); | |
113 | switch (ctx->key_len) { | |
114 | case AES_KEYSIZE_256: | |
115 | key_pos -= 2; | |
116 | /* fall */ | |
117 | case AES_KEYSIZE_192: | |
118 | key_pos -= 2; | |
119 | memcpy(&ctx->aes_dec_key[4], &gen_aes_key.key_enc[key_pos], | |
120 | 4 * 4); | |
121 | break; | |
122 | } | |
123 | ctx->need_calc_aes_dkey = 0; | |
124 | } | |
125 | ||
126 | static int mv_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key, | |
127 | unsigned int len) | |
128 | { | |
129 | struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); | |
130 | struct mv_ctx *ctx = crypto_tfm_ctx(tfm); | |
131 | ||
132 | switch (len) { | |
133 | case AES_KEYSIZE_128: | |
134 | case AES_KEYSIZE_192: | |
135 | case AES_KEYSIZE_256: | |
136 | break; | |
137 | default: | |
138 | crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); | |
139 | return -EINVAL; | |
140 | } | |
141 | ctx->key_len = len; | |
142 | ctx->need_calc_aes_dkey = 1; | |
143 | ||
144 | memcpy(ctx->aes_enc_key, key, AES_KEY_LEN); | |
145 | return 0; | |
146 | } | |
147 | ||
15d4dd35 | 148 | static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len) |
85a7f0ac SAS |
149 | { |
150 | int ret; | |
15d4dd35 US |
151 | void *sbuf; |
152 | int copied = 0; | |
85a7f0ac | 153 | |
15d4dd35 US |
154 | while (1) { |
155 | if (!p->sg_src_left) { | |
156 | ret = sg_miter_next(&p->src_sg_it); | |
157 | BUG_ON(!ret); | |
158 | p->sg_src_left = p->src_sg_it.length; | |
159 | p->src_start = 0; | |
160 | } | |
85a7f0ac | 161 | |
15d4dd35 US |
162 | sbuf = p->src_sg_it.addr + p->src_start; |
163 | ||
164 | if (p->sg_src_left <= len - copied) { | |
165 | memcpy(dbuf + copied, sbuf, p->sg_src_left); | |
166 | copied += p->sg_src_left; | |
167 | p->sg_src_left = 0; | |
168 | if (copied >= len) | |
169 | break; | |
170 | } else { | |
171 | int copy_len = len - copied; | |
172 | memcpy(dbuf + copied, sbuf, copy_len); | |
173 | p->src_start += copy_len; | |
174 | p->sg_src_left -= copy_len; | |
175 | break; | |
176 | } | |
177 | } | |
178 | } | |
85a7f0ac | 179 | |
3b61a905 | 180 | static void setup_data_in(void) |
15d4dd35 US |
181 | { |
182 | struct req_progress *p = &cpg->p; | |
183 | p->crypt_len = | |
7a5f691e | 184 | min(p->hw_nbytes - p->hw_processed_bytes, cpg->max_req_size); |
15d4dd35 US |
185 | copy_src_to_buf(p, cpg->sram + SRAM_DATA_IN_START, |
186 | p->crypt_len); | |
85a7f0ac SAS |
187 | } |
188 | ||
189 | static void mv_process_current_q(int first_block) | |
190 | { | |
3b61a905 | 191 | struct ablkcipher_request *req = ablkcipher_request_cast(cpg->cur_req); |
85a7f0ac SAS |
192 | struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); |
193 | struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | |
194 | struct sec_accel_config op; | |
195 | ||
196 | switch (req_ctx->op) { | |
197 | case COP_AES_ECB: | |
198 | op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_ECB; | |
199 | break; | |
200 | case COP_AES_CBC: | |
6bc6fcd6 | 201 | default: |
85a7f0ac SAS |
202 | op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_CBC; |
203 | op.enc_iv = ENC_IV_POINT(SRAM_DATA_IV) | | |
204 | ENC_IV_BUF_POINT(SRAM_DATA_IV_BUF); | |
205 | if (first_block) | |
206 | memcpy(cpg->sram + SRAM_DATA_IV, req->info, 16); | |
207 | break; | |
208 | } | |
209 | if (req_ctx->decrypt) { | |
210 | op.config |= CFG_DIR_DEC; | |
211 | memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_dec_key, | |
212 | AES_KEY_LEN); | |
213 | } else { | |
214 | op.config |= CFG_DIR_ENC; | |
215 | memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_enc_key, | |
216 | AES_KEY_LEN); | |
217 | } | |
218 | ||
219 | switch (ctx->key_len) { | |
220 | case AES_KEYSIZE_128: | |
221 | op.config |= CFG_AES_LEN_128; | |
222 | break; | |
223 | case AES_KEYSIZE_192: | |
224 | op.config |= CFG_AES_LEN_192; | |
225 | break; | |
226 | case AES_KEYSIZE_256: | |
227 | op.config |= CFG_AES_LEN_256; | |
228 | break; | |
229 | } | |
230 | op.enc_p = ENC_P_SRC(SRAM_DATA_IN_START) | | |
231 | ENC_P_DST(SRAM_DATA_OUT_START); | |
232 | op.enc_key_p = SRAM_DATA_KEY_P; | |
233 | ||
3b61a905 | 234 | setup_data_in(); |
85a7f0ac SAS |
235 | op.enc_len = cpg->p.crypt_len; |
236 | memcpy(cpg->sram + SRAM_CONFIG, &op, | |
237 | sizeof(struct sec_accel_config)); | |
238 | ||
239 | writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); | |
240 | /* GO */ | |
241 | writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); | |
242 | ||
243 | /* | |
244 | * XXX: add timer if the interrupt does not occur for some mystery | |
245 | * reason | |
246 | */ | |
247 | } | |
248 | ||
249 | static void mv_crypto_algo_completion(void) | |
250 | { | |
3b61a905 | 251 | struct ablkcipher_request *req = ablkcipher_request_cast(cpg->cur_req); |
85a7f0ac SAS |
252 | struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); |
253 | ||
254 | if (req_ctx->op != COP_AES_CBC) | |
255 | return ; | |
256 | ||
257 | memcpy(req->info, cpg->sram + SRAM_DATA_IV_BUF, 16); | |
258 | } | |
259 | ||
260 | static void dequeue_complete_req(void) | |
261 | { | |
3b61a905 | 262 | struct crypto_async_request *req = cpg->cur_req; |
85a7f0ac SAS |
263 | void *buf; |
264 | int ret; | |
f565e67e US |
265 | int need_copy_len = cpg->p.crypt_len; |
266 | int sram_offset = 0; | |
85a7f0ac | 267 | |
7a5f691e | 268 | cpg->p.hw_processed_bytes += cpg->p.crypt_len; |
85a7f0ac SAS |
269 | do { |
270 | int dst_copy; | |
271 | ||
272 | if (!cpg->p.sg_dst_left) { | |
273 | ret = sg_miter_next(&cpg->p.dst_sg_it); | |
274 | BUG_ON(!ret); | |
275 | cpg->p.sg_dst_left = cpg->p.dst_sg_it.length; | |
276 | cpg->p.dst_start = 0; | |
277 | } | |
278 | ||
279 | buf = cpg->p.dst_sg_it.addr; | |
280 | buf += cpg->p.dst_start; | |
281 | ||
f565e67e | 282 | dst_copy = min(need_copy_len, cpg->p.sg_dst_left); |
85a7f0ac | 283 | |
f565e67e US |
284 | memcpy(buf, |
285 | cpg->sram + SRAM_DATA_OUT_START + sram_offset, | |
286 | dst_copy); | |
287 | sram_offset += dst_copy; | |
85a7f0ac | 288 | cpg->p.sg_dst_left -= dst_copy; |
f565e67e | 289 | need_copy_len -= dst_copy; |
85a7f0ac | 290 | cpg->p.dst_start += dst_copy; |
f565e67e | 291 | } while (need_copy_len > 0); |
85a7f0ac SAS |
292 | |
293 | BUG_ON(cpg->eng_st != ENGINE_W_DEQUEUE); | |
7a5f691e | 294 | if (cpg->p.hw_processed_bytes < cpg->p.hw_nbytes) { |
85a7f0ac SAS |
295 | /* process next scatter list entry */ |
296 | cpg->eng_st = ENGINE_BUSY; | |
297 | mv_process_current_q(0); | |
298 | } else { | |
299 | sg_miter_stop(&cpg->p.src_sg_it); | |
300 | sg_miter_stop(&cpg->p.dst_sg_it); | |
301 | mv_crypto_algo_completion(); | |
302 | cpg->eng_st = ENGINE_IDLE; | |
0328ac26 | 303 | local_bh_disable(); |
3b61a905 | 304 | req->complete(req, 0); |
0328ac26 | 305 | local_bh_enable(); |
85a7f0ac SAS |
306 | } |
307 | } | |
308 | ||
309 | static int count_sgs(struct scatterlist *sl, unsigned int total_bytes) | |
310 | { | |
311 | int i = 0; | |
15d4dd35 US |
312 | size_t cur_len; |
313 | ||
314 | while (1) { | |
315 | cur_len = sl[i].length; | |
316 | ++i; | |
317 | if (total_bytes > cur_len) | |
318 | total_bytes -= cur_len; | |
319 | else | |
320 | break; | |
321 | } | |
85a7f0ac SAS |
322 | |
323 | return i; | |
324 | } | |
325 | ||
326 | static void mv_enqueue_new_req(struct ablkcipher_request *req) | |
327 | { | |
3b61a905 | 328 | struct req_progress *p = &cpg->p; |
85a7f0ac SAS |
329 | int num_sgs; |
330 | ||
3b61a905 US |
331 | cpg->cur_req = &req->base; |
332 | memset(p, 0, sizeof(struct req_progress)); | |
333 | p->hw_nbytes = req->nbytes; | |
85a7f0ac SAS |
334 | |
335 | num_sgs = count_sgs(req->src, req->nbytes); | |
3b61a905 | 336 | sg_miter_start(&p->src_sg_it, req->src, num_sgs, SG_MITER_FROM_SG); |
85a7f0ac SAS |
337 | |
338 | num_sgs = count_sgs(req->dst, req->nbytes); | |
3b61a905 US |
339 | sg_miter_start(&p->dst_sg_it, req->dst, num_sgs, SG_MITER_TO_SG); |
340 | ||
85a7f0ac SAS |
341 | mv_process_current_q(1); |
342 | } | |
343 | ||
344 | static int queue_manag(void *data) | |
345 | { | |
346 | cpg->eng_st = ENGINE_IDLE; | |
347 | do { | |
348 | struct ablkcipher_request *req; | |
349 | struct crypto_async_request *async_req = NULL; | |
350 | struct crypto_async_request *backlog; | |
351 | ||
352 | __set_current_state(TASK_INTERRUPTIBLE); | |
353 | ||
354 | if (cpg->eng_st == ENGINE_W_DEQUEUE) | |
355 | dequeue_complete_req(); | |
356 | ||
357 | spin_lock_irq(&cpg->lock); | |
358 | if (cpg->eng_st == ENGINE_IDLE) { | |
359 | backlog = crypto_get_backlog(&cpg->queue); | |
360 | async_req = crypto_dequeue_request(&cpg->queue); | |
361 | if (async_req) { | |
362 | BUG_ON(cpg->eng_st != ENGINE_IDLE); | |
363 | cpg->eng_st = ENGINE_BUSY; | |
364 | } | |
365 | } | |
366 | spin_unlock_irq(&cpg->lock); | |
367 | ||
368 | if (backlog) { | |
369 | backlog->complete(backlog, -EINPROGRESS); | |
370 | backlog = NULL; | |
371 | } | |
372 | ||
373 | if (async_req) { | |
374 | req = container_of(async_req, | |
375 | struct ablkcipher_request, base); | |
376 | mv_enqueue_new_req(req); | |
377 | async_req = NULL; | |
378 | } | |
379 | ||
380 | schedule(); | |
381 | ||
382 | } while (!kthread_should_stop()); | |
383 | return 0; | |
384 | } | |
385 | ||
3b61a905 | 386 | static int mv_handle_req(struct crypto_async_request *req) |
85a7f0ac SAS |
387 | { |
388 | unsigned long flags; | |
389 | int ret; | |
390 | ||
391 | spin_lock_irqsave(&cpg->lock, flags); | |
3b61a905 | 392 | ret = crypto_enqueue_request(&cpg->queue, req); |
85a7f0ac SAS |
393 | spin_unlock_irqrestore(&cpg->lock, flags); |
394 | wake_up_process(cpg->queue_th); | |
395 | return ret; | |
396 | } | |
397 | ||
398 | static int mv_enc_aes_ecb(struct ablkcipher_request *req) | |
399 | { | |
400 | struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | |
401 | ||
402 | req_ctx->op = COP_AES_ECB; | |
403 | req_ctx->decrypt = 0; | |
404 | ||
3b61a905 | 405 | return mv_handle_req(&req->base); |
85a7f0ac SAS |
406 | } |
407 | ||
408 | static int mv_dec_aes_ecb(struct ablkcipher_request *req) | |
409 | { | |
410 | struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
411 | struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | |
412 | ||
413 | req_ctx->op = COP_AES_ECB; | |
414 | req_ctx->decrypt = 1; | |
415 | ||
416 | compute_aes_dec_key(ctx); | |
3b61a905 | 417 | return mv_handle_req(&req->base); |
85a7f0ac SAS |
418 | } |
419 | ||
420 | static int mv_enc_aes_cbc(struct ablkcipher_request *req) | |
421 | { | |
422 | struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | |
423 | ||
424 | req_ctx->op = COP_AES_CBC; | |
425 | req_ctx->decrypt = 0; | |
426 | ||
3b61a905 | 427 | return mv_handle_req(&req->base); |
85a7f0ac SAS |
428 | } |
429 | ||
430 | static int mv_dec_aes_cbc(struct ablkcipher_request *req) | |
431 | { | |
432 | struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | |
433 | struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); | |
434 | ||
435 | req_ctx->op = COP_AES_CBC; | |
436 | req_ctx->decrypt = 1; | |
437 | ||
438 | compute_aes_dec_key(ctx); | |
3b61a905 | 439 | return mv_handle_req(&req->base); |
85a7f0ac SAS |
440 | } |
441 | ||
442 | static int mv_cra_init(struct crypto_tfm *tfm) | |
443 | { | |
444 | tfm->crt_ablkcipher.reqsize = sizeof(struct mv_req_ctx); | |
445 | return 0; | |
446 | } | |
447 | ||
448 | irqreturn_t crypto_int(int irq, void *priv) | |
449 | { | |
450 | u32 val; | |
451 | ||
452 | val = readl(cpg->reg + SEC_ACCEL_INT_STATUS); | |
453 | if (!(val & SEC_INT_ACCEL0_DONE)) | |
454 | return IRQ_NONE; | |
455 | ||
456 | val &= ~SEC_INT_ACCEL0_DONE; | |
457 | writel(val, cpg->reg + FPGA_INT_STATUS); | |
458 | writel(val, cpg->reg + SEC_ACCEL_INT_STATUS); | |
459 | BUG_ON(cpg->eng_st != ENGINE_BUSY); | |
460 | cpg->eng_st = ENGINE_W_DEQUEUE; | |
461 | wake_up_process(cpg->queue_th); | |
462 | return IRQ_HANDLED; | |
463 | } | |
464 | ||
465 | struct crypto_alg mv_aes_alg_ecb = { | |
466 | .cra_name = "ecb(aes)", | |
467 | .cra_driver_name = "mv-ecb-aes", | |
468 | .cra_priority = 300, | |
469 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, | |
470 | .cra_blocksize = 16, | |
471 | .cra_ctxsize = sizeof(struct mv_ctx), | |
472 | .cra_alignmask = 0, | |
473 | .cra_type = &crypto_ablkcipher_type, | |
474 | .cra_module = THIS_MODULE, | |
475 | .cra_init = mv_cra_init, | |
476 | .cra_u = { | |
477 | .ablkcipher = { | |
478 | .min_keysize = AES_MIN_KEY_SIZE, | |
479 | .max_keysize = AES_MAX_KEY_SIZE, | |
480 | .setkey = mv_setkey_aes, | |
481 | .encrypt = mv_enc_aes_ecb, | |
482 | .decrypt = mv_dec_aes_ecb, | |
483 | }, | |
484 | }, | |
485 | }; | |
486 | ||
487 | struct crypto_alg mv_aes_alg_cbc = { | |
488 | .cra_name = "cbc(aes)", | |
489 | .cra_driver_name = "mv-cbc-aes", | |
490 | .cra_priority = 300, | |
491 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, | |
492 | .cra_blocksize = AES_BLOCK_SIZE, | |
493 | .cra_ctxsize = sizeof(struct mv_ctx), | |
494 | .cra_alignmask = 0, | |
495 | .cra_type = &crypto_ablkcipher_type, | |
496 | .cra_module = THIS_MODULE, | |
497 | .cra_init = mv_cra_init, | |
498 | .cra_u = { | |
499 | .ablkcipher = { | |
500 | .ivsize = AES_BLOCK_SIZE, | |
501 | .min_keysize = AES_MIN_KEY_SIZE, | |
502 | .max_keysize = AES_MAX_KEY_SIZE, | |
503 | .setkey = mv_setkey_aes, | |
504 | .encrypt = mv_enc_aes_cbc, | |
505 | .decrypt = mv_dec_aes_cbc, | |
506 | }, | |
507 | }, | |
508 | }; | |
509 | ||
510 | static int mv_probe(struct platform_device *pdev) | |
511 | { | |
512 | struct crypto_priv *cp; | |
513 | struct resource *res; | |
514 | int irq; | |
515 | int ret; | |
516 | ||
517 | if (cpg) { | |
518 | printk(KERN_ERR "Second crypto dev?\n"); | |
519 | return -EEXIST; | |
520 | } | |
521 | ||
522 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | |
523 | if (!res) | |
524 | return -ENXIO; | |
525 | ||
526 | cp = kzalloc(sizeof(*cp), GFP_KERNEL); | |
527 | if (!cp) | |
528 | return -ENOMEM; | |
529 | ||
530 | spin_lock_init(&cp->lock); | |
531 | crypto_init_queue(&cp->queue, 50); | |
532 | cp->reg = ioremap(res->start, res->end - res->start + 1); | |
533 | if (!cp->reg) { | |
534 | ret = -ENOMEM; | |
535 | goto err; | |
536 | } | |
537 | ||
538 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); | |
539 | if (!res) { | |
540 | ret = -ENXIO; | |
541 | goto err_unmap_reg; | |
542 | } | |
543 | cp->sram_size = res->end - res->start + 1; | |
544 | cp->max_req_size = cp->sram_size - SRAM_CFG_SPACE; | |
545 | cp->sram = ioremap(res->start, cp->sram_size); | |
546 | if (!cp->sram) { | |
547 | ret = -ENOMEM; | |
548 | goto err_unmap_reg; | |
549 | } | |
550 | ||
551 | irq = platform_get_irq(pdev, 0); | |
552 | if (irq < 0 || irq == NO_IRQ) { | |
553 | ret = irq; | |
554 | goto err_unmap_sram; | |
555 | } | |
556 | cp->irq = irq; | |
557 | ||
558 | platform_set_drvdata(pdev, cp); | |
559 | cpg = cp; | |
560 | ||
561 | cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto"); | |
562 | if (IS_ERR(cp->queue_th)) { | |
563 | ret = PTR_ERR(cp->queue_th); | |
564 | goto err_thread; | |
565 | } | |
566 | ||
567 | ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev), | |
568 | cp); | |
569 | if (ret) | |
570 | goto err_unmap_sram; | |
571 | ||
572 | writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); | |
573 | writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); | |
574 | ||
575 | ret = crypto_register_alg(&mv_aes_alg_ecb); | |
576 | if (ret) | |
577 | goto err_reg; | |
578 | ||
579 | ret = crypto_register_alg(&mv_aes_alg_cbc); | |
580 | if (ret) | |
581 | goto err_unreg_ecb; | |
582 | return 0; | |
583 | err_unreg_ecb: | |
584 | crypto_unregister_alg(&mv_aes_alg_ecb); | |
585 | err_thread: | |
586 | free_irq(irq, cp); | |
587 | err_reg: | |
588 | kthread_stop(cp->queue_th); | |
589 | err_unmap_sram: | |
590 | iounmap(cp->sram); | |
591 | err_unmap_reg: | |
592 | iounmap(cp->reg); | |
593 | err: | |
594 | kfree(cp); | |
595 | cpg = NULL; | |
596 | platform_set_drvdata(pdev, NULL); | |
597 | return ret; | |
598 | } | |
599 | ||
600 | static int mv_remove(struct platform_device *pdev) | |
601 | { | |
602 | struct crypto_priv *cp = platform_get_drvdata(pdev); | |
603 | ||
604 | crypto_unregister_alg(&mv_aes_alg_ecb); | |
605 | crypto_unregister_alg(&mv_aes_alg_cbc); | |
606 | kthread_stop(cp->queue_th); | |
607 | free_irq(cp->irq, cp); | |
608 | memset(cp->sram, 0, cp->sram_size); | |
609 | iounmap(cp->sram); | |
610 | iounmap(cp->reg); | |
611 | kfree(cp); | |
612 | cpg = NULL; | |
613 | return 0; | |
614 | } | |
615 | ||
616 | static struct platform_driver marvell_crypto = { | |
617 | .probe = mv_probe, | |
618 | .remove = mv_remove, | |
619 | .driver = { | |
620 | .owner = THIS_MODULE, | |
621 | .name = "mv_crypto", | |
622 | }, | |
623 | }; | |
624 | MODULE_ALIAS("platform:mv_crypto"); | |
625 | ||
626 | static int __init mv_crypto_init(void) | |
627 | { | |
628 | return platform_driver_register(&marvell_crypto); | |
629 | } | |
630 | module_init(mv_crypto_init); | |
631 | ||
632 | static void __exit mv_crypto_exit(void) | |
633 | { | |
634 | platform_driver_unregister(&marvell_crypto); | |
635 | } | |
636 | module_exit(mv_crypto_exit); | |
637 | ||
638 | MODULE_AUTHOR("Sebastian Andrzej Siewior <sebastian@breakpoint.cc>"); | |
639 | MODULE_DESCRIPTION("Support for Marvell's cryptographic engine"); | |
640 | MODULE_LICENSE("GPL"); |