Root/
1 | /* |
2 | * Cryptographic API. |
3 | * |
4 | * Support for ATMEL DES/TDES HW acceleration. |
5 | * |
6 | * Copyright (c) 2012 Eukréa Electromatique - ATMEL |
7 | * Author: Nicolas Royer <nicolas@eukrea.com> |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as published |
11 | * by the Free Software Foundation. |
12 | * |
13 | * Some ideas are from omap-aes.c drivers. |
14 | */ |
15 | |
16 | |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/err.h> |
21 | #include <linux/clk.h> |
22 | #include <linux/io.h> |
23 | #include <linux/hw_random.h> |
24 | #include <linux/platform_device.h> |
25 | |
26 | #include <linux/device.h> |
27 | #include <linux/module.h> |
28 | #include <linux/init.h> |
29 | #include <linux/errno.h> |
30 | #include <linux/interrupt.h> |
31 | #include <linux/kernel.h> |
32 | #include <linux/clk.h> |
33 | #include <linux/irq.h> |
34 | #include <linux/io.h> |
35 | #include <linux/platform_device.h> |
36 | #include <linux/scatterlist.h> |
37 | #include <linux/dma-mapping.h> |
38 | #include <linux/delay.h> |
39 | #include <linux/crypto.h> |
40 | #include <linux/cryptohash.h> |
41 | #include <crypto/scatterwalk.h> |
42 | #include <crypto/algapi.h> |
43 | #include <crypto/des.h> |
44 | #include <crypto/hash.h> |
45 | #include <crypto/internal/hash.h> |
46 | #include "atmel-tdes-regs.h" |
47 | |
48 | /* TDES flags */ |
49 | #define TDES_FLAGS_MODE_MASK 0x007f |
50 | #define TDES_FLAGS_ENCRYPT BIT(0) |
51 | #define TDES_FLAGS_CBC BIT(1) |
52 | #define TDES_FLAGS_CFB BIT(2) |
53 | #define TDES_FLAGS_CFB8 BIT(3) |
54 | #define TDES_FLAGS_CFB16 BIT(4) |
55 | #define TDES_FLAGS_CFB32 BIT(5) |
56 | #define TDES_FLAGS_OFB BIT(6) |
57 | |
58 | #define TDES_FLAGS_INIT BIT(16) |
59 | #define TDES_FLAGS_FAST BIT(17) |
60 | #define TDES_FLAGS_BUSY BIT(18) |
61 | |
62 | #define ATMEL_TDES_QUEUE_LENGTH 1 |
63 | |
64 | #define CFB8_BLOCK_SIZE 1 |
65 | #define CFB16_BLOCK_SIZE 2 |
66 | #define CFB32_BLOCK_SIZE 4 |
67 | #define CFB64_BLOCK_SIZE 8 |
68 | |
69 | |
70 | struct atmel_tdes_dev; |
71 | |
72 | struct atmel_tdes_ctx { |
73 | struct atmel_tdes_dev *dd; |
74 | |
75 | int keylen; |
76 | u32 key[3*DES_KEY_SIZE / sizeof(u32)]; |
77 | unsigned long flags; |
78 | }; |
79 | |
80 | struct atmel_tdes_reqctx { |
81 | unsigned long mode; |
82 | }; |
83 | |
84 | struct atmel_tdes_dev { |
85 | struct list_head list; |
86 | unsigned long phys_base; |
87 | void __iomem *io_base; |
88 | |
89 | struct atmel_tdes_ctx *ctx; |
90 | struct device *dev; |
91 | struct clk *iclk; |
92 | int irq; |
93 | |
94 | unsigned long flags; |
95 | int err; |
96 | |
97 | spinlock_t lock; |
98 | struct crypto_queue queue; |
99 | |
100 | struct tasklet_struct done_task; |
101 | struct tasklet_struct queue_task; |
102 | |
103 | struct ablkcipher_request *req; |
104 | size_t total; |
105 | |
106 | struct scatterlist *in_sg; |
107 | size_t in_offset; |
108 | struct scatterlist *out_sg; |
109 | size_t out_offset; |
110 | |
111 | size_t buflen; |
112 | size_t dma_size; |
113 | |
114 | void *buf_in; |
115 | int dma_in; |
116 | dma_addr_t dma_addr_in; |
117 | |
118 | void *buf_out; |
119 | int dma_out; |
120 | dma_addr_t dma_addr_out; |
121 | }; |
122 | |
123 | struct atmel_tdes_drv { |
124 | struct list_head dev_list; |
125 | spinlock_t lock; |
126 | }; |
127 | |
128 | static struct atmel_tdes_drv atmel_tdes = { |
129 | .dev_list = LIST_HEAD_INIT(atmel_tdes.dev_list), |
130 | .lock = __SPIN_LOCK_UNLOCKED(atmel_tdes.lock), |
131 | }; |
132 | |
133 | static int atmel_tdes_sg_copy(struct scatterlist **sg, size_t *offset, |
134 | void *buf, size_t buflen, size_t total, int out) |
135 | { |
136 | unsigned int count, off = 0; |
137 | |
138 | while (buflen && total) { |
139 | count = min((*sg)->length - *offset, total); |
140 | count = min(count, buflen); |
141 | |
142 | if (!count) |
143 | return off; |
144 | |
145 | scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out); |
146 | |
147 | off += count; |
148 | buflen -= count; |
149 | *offset += count; |
150 | total -= count; |
151 | |
152 | if (*offset == (*sg)->length) { |
153 | *sg = sg_next(*sg); |
154 | if (*sg) |
155 | *offset = 0; |
156 | else |
157 | total = 0; |
158 | } |
159 | } |
160 | |
161 | return off; |
162 | } |
163 | |
164 | static inline u32 atmel_tdes_read(struct atmel_tdes_dev *dd, u32 offset) |
165 | { |
166 | return readl_relaxed(dd->io_base + offset); |
167 | } |
168 | |
169 | static inline void atmel_tdes_write(struct atmel_tdes_dev *dd, |
170 | u32 offset, u32 value) |
171 | { |
172 | writel_relaxed(value, dd->io_base + offset); |
173 | } |
174 | |
175 | static void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset, |
176 | u32 *value, int count) |
177 | { |
178 | for (; count--; value++, offset += 4) |
179 | atmel_tdes_write(dd, offset, *value); |
180 | } |
181 | |
182 | static struct atmel_tdes_dev *atmel_tdes_find_dev(struct atmel_tdes_ctx *ctx) |
183 | { |
184 | struct atmel_tdes_dev *tdes_dd = NULL; |
185 | struct atmel_tdes_dev *tmp; |
186 | |
187 | spin_lock_bh(&atmel_tdes.lock); |
188 | if (!ctx->dd) { |
189 | list_for_each_entry(tmp, &atmel_tdes.dev_list, list) { |
190 | tdes_dd = tmp; |
191 | break; |
192 | } |
193 | ctx->dd = tdes_dd; |
194 | } else { |
195 | tdes_dd = ctx->dd; |
196 | } |
197 | spin_unlock_bh(&atmel_tdes.lock); |
198 | |
199 | return tdes_dd; |
200 | } |
201 | |
202 | static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd) |
203 | { |
204 | clk_prepare_enable(dd->iclk); |
205 | |
206 | if (!(dd->flags & TDES_FLAGS_INIT)) { |
207 | atmel_tdes_write(dd, TDES_CR, TDES_CR_SWRST); |
208 | dd->flags |= TDES_FLAGS_INIT; |
209 | dd->err = 0; |
210 | } |
211 | |
212 | return 0; |
213 | } |
214 | |
215 | static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd) |
216 | { |
217 | int err; |
218 | u32 valcr = 0, valmr = TDES_MR_SMOD_PDC; |
219 | |
220 | err = atmel_tdes_hw_init(dd); |
221 | |
222 | if (err) |
223 | return err; |
224 | |
225 | atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); |
226 | |
227 | /* MR register must be set before IV registers */ |
228 | if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) { |
229 | valmr |= TDES_MR_KEYMOD_3KEY; |
230 | valmr |= TDES_MR_TDESMOD_TDES; |
231 | } else if (dd->ctx->keylen > DES_KEY_SIZE) { |
232 | valmr |= TDES_MR_KEYMOD_2KEY; |
233 | valmr |= TDES_MR_TDESMOD_TDES; |
234 | } else { |
235 | valmr |= TDES_MR_TDESMOD_DES; |
236 | } |
237 | |
238 | if (dd->flags & TDES_FLAGS_CBC) { |
239 | valmr |= TDES_MR_OPMOD_CBC; |
240 | } else if (dd->flags & TDES_FLAGS_CFB) { |
241 | valmr |= TDES_MR_OPMOD_CFB; |
242 | |
243 | if (dd->flags & TDES_FLAGS_CFB8) |
244 | valmr |= TDES_MR_CFBS_8b; |
245 | else if (dd->flags & TDES_FLAGS_CFB16) |
246 | valmr |= TDES_MR_CFBS_16b; |
247 | else if (dd->flags & TDES_FLAGS_CFB32) |
248 | valmr |= TDES_MR_CFBS_32b; |
249 | } else if (dd->flags & TDES_FLAGS_OFB) { |
250 | valmr |= TDES_MR_OPMOD_OFB; |
251 | } |
252 | |
253 | if ((dd->flags & TDES_FLAGS_ENCRYPT) || (dd->flags & TDES_FLAGS_OFB)) |
254 | valmr |= TDES_MR_CYPHER_ENC; |
255 | |
256 | atmel_tdes_write(dd, TDES_CR, valcr); |
257 | atmel_tdes_write(dd, TDES_MR, valmr); |
258 | |
259 | atmel_tdes_write_n(dd, TDES_KEY1W1R, dd->ctx->key, |
260 | dd->ctx->keylen >> 2); |
261 | |
262 | if (((dd->flags & TDES_FLAGS_CBC) || (dd->flags & TDES_FLAGS_CFB) || |
263 | (dd->flags & TDES_FLAGS_OFB)) && dd->req->info) { |
264 | atmel_tdes_write_n(dd, TDES_IV1R, dd->req->info, 2); |
265 | } |
266 | |
267 | return 0; |
268 | } |
269 | |
270 | static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd) |
271 | { |
272 | int err = 0; |
273 | size_t count; |
274 | |
275 | atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); |
276 | |
277 | if (dd->flags & TDES_FLAGS_FAST) { |
278 | dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); |
279 | dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); |
280 | } else { |
281 | dma_sync_single_for_device(dd->dev, dd->dma_addr_out, |
282 | dd->dma_size, DMA_FROM_DEVICE); |
283 | |
284 | /* copy data */ |
285 | count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset, |
286 | dd->buf_out, dd->buflen, dd->dma_size, 1); |
287 | if (count != dd->dma_size) { |
288 | err = -EINVAL; |
289 | pr_err("not all data converted: %u\n", count); |
290 | } |
291 | } |
292 | |
293 | return err; |
294 | } |
295 | |
296 | static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd) |
297 | { |
298 | int err = -ENOMEM; |
299 | |
300 | dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0); |
301 | dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0); |
302 | dd->buflen = PAGE_SIZE; |
303 | dd->buflen &= ~(DES_BLOCK_SIZE - 1); |
304 | |
305 | if (!dd->buf_in || !dd->buf_out) { |
306 | dev_err(dd->dev, "unable to alloc pages.\n"); |
307 | goto err_alloc; |
308 | } |
309 | |
310 | /* MAP here */ |
311 | dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, |
312 | dd->buflen, DMA_TO_DEVICE); |
313 | if (dma_mapping_error(dd->dev, dd->dma_addr_in)) { |
314 | dev_err(dd->dev, "dma %d bytes error\n", dd->buflen); |
315 | err = -EINVAL; |
316 | goto err_map_in; |
317 | } |
318 | |
319 | dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, |
320 | dd->buflen, DMA_FROM_DEVICE); |
321 | if (dma_mapping_error(dd->dev, dd->dma_addr_out)) { |
322 | dev_err(dd->dev, "dma %d bytes error\n", dd->buflen); |
323 | err = -EINVAL; |
324 | goto err_map_out; |
325 | } |
326 | |
327 | return 0; |
328 | |
329 | err_map_out: |
330 | dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, |
331 | DMA_TO_DEVICE); |
332 | err_map_in: |
333 | free_page((unsigned long)dd->buf_out); |
334 | free_page((unsigned long)dd->buf_in); |
335 | err_alloc: |
336 | if (err) |
337 | pr_err("error: %d\n", err); |
338 | return err; |
339 | } |
340 | |
341 | static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd) |
342 | { |
343 | dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen, |
344 | DMA_FROM_DEVICE); |
345 | dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, |
346 | DMA_TO_DEVICE); |
347 | free_page((unsigned long)dd->buf_out); |
348 | free_page((unsigned long)dd->buf_in); |
349 | } |
350 | |
351 | static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, |
352 | dma_addr_t dma_addr_out, int length) |
353 | { |
354 | struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm); |
355 | struct atmel_tdes_dev *dd = ctx->dd; |
356 | int len32; |
357 | |
358 | dd->dma_size = length; |
359 | |
360 | if (!(dd->flags & TDES_FLAGS_FAST)) { |
361 | dma_sync_single_for_device(dd->dev, dma_addr_in, length, |
362 | DMA_TO_DEVICE); |
363 | } |
364 | |
365 | if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB8)) |
366 | len32 = DIV_ROUND_UP(length, sizeof(u8)); |
367 | else if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB16)) |
368 | len32 = DIV_ROUND_UP(length, sizeof(u16)); |
369 | else |
370 | len32 = DIV_ROUND_UP(length, sizeof(u32)); |
371 | |
372 | atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); |
373 | atmel_tdes_write(dd, TDES_TPR, dma_addr_in); |
374 | atmel_tdes_write(dd, TDES_TCR, len32); |
375 | atmel_tdes_write(dd, TDES_RPR, dma_addr_out); |
376 | atmel_tdes_write(dd, TDES_RCR, len32); |
377 | |
378 | /* Enable Interrupt */ |
379 | atmel_tdes_write(dd, TDES_IER, TDES_INT_ENDRX); |
380 | |
381 | /* Start DMA transfer */ |
382 | atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTEN | TDES_PTCR_RXTEN); |
383 | |
384 | return 0; |
385 | } |
386 | |
387 | static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd) |
388 | { |
389 | struct crypto_tfm *tfm = crypto_ablkcipher_tfm( |
390 | crypto_ablkcipher_reqtfm(dd->req)); |
391 | int err, fast = 0, in, out; |
392 | size_t count; |
393 | dma_addr_t addr_in, addr_out; |
394 | |
395 | if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) { |
396 | /* check for alignment */ |
397 | in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)); |
398 | out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)); |
399 | |
400 | fast = in && out; |
401 | } |
402 | |
403 | if (fast) { |
404 | count = min(dd->total, sg_dma_len(dd->in_sg)); |
405 | count = min(count, sg_dma_len(dd->out_sg)); |
406 | |
407 | if (count != dd->total) { |
408 | pr_err("request length != buffer length\n"); |
409 | return -EINVAL; |
410 | } |
411 | |
412 | err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); |
413 | if (!err) { |
414 | dev_err(dd->dev, "dma_map_sg() error\n"); |
415 | return -EINVAL; |
416 | } |
417 | |
418 | err = dma_map_sg(dd->dev, dd->out_sg, 1, |
419 | DMA_FROM_DEVICE); |
420 | if (!err) { |
421 | dev_err(dd->dev, "dma_map_sg() error\n"); |
422 | dma_unmap_sg(dd->dev, dd->in_sg, 1, |
423 | DMA_TO_DEVICE); |
424 | return -EINVAL; |
425 | } |
426 | |
427 | addr_in = sg_dma_address(dd->in_sg); |
428 | addr_out = sg_dma_address(dd->out_sg); |
429 | |
430 | dd->flags |= TDES_FLAGS_FAST; |
431 | |
432 | } else { |
433 | /* use cache buffers */ |
434 | count = atmel_tdes_sg_copy(&dd->in_sg, &dd->in_offset, |
435 | dd->buf_in, dd->buflen, dd->total, 0); |
436 | |
437 | addr_in = dd->dma_addr_in; |
438 | addr_out = dd->dma_addr_out; |
439 | |
440 | dd->flags &= ~TDES_FLAGS_FAST; |
441 | |
442 | } |
443 | |
444 | dd->total -= count; |
445 | |
446 | err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count); |
447 | if (err) { |
448 | dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); |
449 | dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE); |
450 | } |
451 | |
452 | return err; |
453 | } |
454 | |
455 | |
456 | static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err) |
457 | { |
458 | struct ablkcipher_request *req = dd->req; |
459 | |
460 | clk_disable_unprepare(dd->iclk); |
461 | |
462 | dd->flags &= ~TDES_FLAGS_BUSY; |
463 | |
464 | req->base.complete(&req->base, err); |
465 | } |
466 | |
467 | static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd, |
468 | struct ablkcipher_request *req) |
469 | { |
470 | struct crypto_async_request *async_req, *backlog; |
471 | struct atmel_tdes_ctx *ctx; |
472 | struct atmel_tdes_reqctx *rctx; |
473 | unsigned long flags; |
474 | int err, ret = 0; |
475 | |
476 | spin_lock_irqsave(&dd->lock, flags); |
477 | if (req) |
478 | ret = ablkcipher_enqueue_request(&dd->queue, req); |
479 | if (dd->flags & TDES_FLAGS_BUSY) { |
480 | spin_unlock_irqrestore(&dd->lock, flags); |
481 | return ret; |
482 | } |
483 | backlog = crypto_get_backlog(&dd->queue); |
484 | async_req = crypto_dequeue_request(&dd->queue); |
485 | if (async_req) |
486 | dd->flags |= TDES_FLAGS_BUSY; |
487 | spin_unlock_irqrestore(&dd->lock, flags); |
488 | |
489 | if (!async_req) |
490 | return ret; |
491 | |
492 | if (backlog) |
493 | backlog->complete(backlog, -EINPROGRESS); |
494 | |
495 | req = ablkcipher_request_cast(async_req); |
496 | |
497 | /* assign new request to device */ |
498 | dd->req = req; |
499 | dd->total = req->nbytes; |
500 | dd->in_offset = 0; |
501 | dd->in_sg = req->src; |
502 | dd->out_offset = 0; |
503 | dd->out_sg = req->dst; |
504 | |
505 | rctx = ablkcipher_request_ctx(req); |
506 | ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); |
507 | rctx->mode &= TDES_FLAGS_MODE_MASK; |
508 | dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode; |
509 | dd->ctx = ctx; |
510 | ctx->dd = dd; |
511 | |
512 | err = atmel_tdes_write_ctrl(dd); |
513 | if (!err) |
514 | err = atmel_tdes_crypt_dma_start(dd); |
515 | if (err) { |
516 | /* des_task will not finish it, so do it here */ |
517 | atmel_tdes_finish_req(dd, err); |
518 | tasklet_schedule(&dd->queue_task); |
519 | } |
520 | |
521 | return ret; |
522 | } |
523 | |
524 | |
525 | static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode) |
526 | { |
527 | struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx( |
528 | crypto_ablkcipher_reqtfm(req)); |
529 | struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req); |
530 | struct atmel_tdes_dev *dd; |
531 | |
532 | if (mode & TDES_FLAGS_CFB8) { |
533 | if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) { |
534 | pr_err("request size is not exact amount of CFB8 blocks\n"); |
535 | return -EINVAL; |
536 | } |
537 | } else if (mode & TDES_FLAGS_CFB16) { |
538 | if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) { |
539 | pr_err("request size is not exact amount of CFB16 blocks\n"); |
540 | return -EINVAL; |
541 | } |
542 | } else if (mode & TDES_FLAGS_CFB32) { |
543 | if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) { |
544 | pr_err("request size is not exact amount of CFB32 blocks\n"); |
545 | return -EINVAL; |
546 | } |
547 | } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) { |
548 | pr_err("request size is not exact amount of DES blocks\n"); |
549 | return -EINVAL; |
550 | } |
551 | |
552 | dd = atmel_tdes_find_dev(ctx); |
553 | if (!dd) |
554 | return -ENODEV; |
555 | |
556 | rctx->mode = mode; |
557 | |
558 | return atmel_tdes_handle_queue(dd, req); |
559 | } |
560 | |
561 | static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, |
562 | unsigned int keylen) |
563 | { |
564 | u32 tmp[DES_EXPKEY_WORDS]; |
565 | int err; |
566 | struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm); |
567 | |
568 | struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm); |
569 | |
570 | if (keylen != DES_KEY_SIZE) { |
571 | crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); |
572 | return -EINVAL; |
573 | } |
574 | |
575 | err = des_ekey(tmp, key); |
576 | if (err == 0 && (ctfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) { |
577 | ctfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; |
578 | return -EINVAL; |
579 | } |
580 | |
581 | memcpy(ctx->key, key, keylen); |
582 | ctx->keylen = keylen; |
583 | |
584 | return 0; |
585 | } |
586 | |
587 | static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, |
588 | unsigned int keylen) |
589 | { |
590 | struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm); |
591 | const char *alg_name; |
592 | |
593 | alg_name = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm)); |
594 | |
595 | /* |
596 | * HW bug in cfb 3-keys mode. |
597 | */ |
598 | if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) { |
599 | crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); |
600 | return -EINVAL; |
601 | } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) { |
602 | crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); |
603 | return -EINVAL; |
604 | } |
605 | |
606 | memcpy(ctx->key, key, keylen); |
607 | ctx->keylen = keylen; |
608 | |
609 | return 0; |
610 | } |
611 | |
612 | static int atmel_tdes_ecb_encrypt(struct ablkcipher_request *req) |
613 | { |
614 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT); |
615 | } |
616 | |
617 | static int atmel_tdes_ecb_decrypt(struct ablkcipher_request *req) |
618 | { |
619 | return atmel_tdes_crypt(req, 0); |
620 | } |
621 | |
622 | static int atmel_tdes_cbc_encrypt(struct ablkcipher_request *req) |
623 | { |
624 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CBC); |
625 | } |
626 | |
627 | static int atmel_tdes_cbc_decrypt(struct ablkcipher_request *req) |
628 | { |
629 | return atmel_tdes_crypt(req, TDES_FLAGS_CBC); |
630 | } |
631 | static int atmel_tdes_cfb_encrypt(struct ablkcipher_request *req) |
632 | { |
633 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB); |
634 | } |
635 | |
636 | static int atmel_tdes_cfb_decrypt(struct ablkcipher_request *req) |
637 | { |
638 | return atmel_tdes_crypt(req, TDES_FLAGS_CFB); |
639 | } |
640 | |
641 | static int atmel_tdes_cfb8_encrypt(struct ablkcipher_request *req) |
642 | { |
643 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB | |
644 | TDES_FLAGS_CFB8); |
645 | } |
646 | |
647 | static int atmel_tdes_cfb8_decrypt(struct ablkcipher_request *req) |
648 | { |
649 | return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB8); |
650 | } |
651 | |
652 | static int atmel_tdes_cfb16_encrypt(struct ablkcipher_request *req) |
653 | { |
654 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB | |
655 | TDES_FLAGS_CFB16); |
656 | } |
657 | |
658 | static int atmel_tdes_cfb16_decrypt(struct ablkcipher_request *req) |
659 | { |
660 | return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB16); |
661 | } |
662 | |
663 | static int atmel_tdes_cfb32_encrypt(struct ablkcipher_request *req) |
664 | { |
665 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB | |
666 | TDES_FLAGS_CFB32); |
667 | } |
668 | |
669 | static int atmel_tdes_cfb32_decrypt(struct ablkcipher_request *req) |
670 | { |
671 | return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB32); |
672 | } |
673 | |
674 | static int atmel_tdes_ofb_encrypt(struct ablkcipher_request *req) |
675 | { |
676 | return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_OFB); |
677 | } |
678 | |
679 | static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req) |
680 | { |
681 | return atmel_tdes_crypt(req, TDES_FLAGS_OFB); |
682 | } |
683 | |
684 | static int atmel_tdes_cra_init(struct crypto_tfm *tfm) |
685 | { |
686 | tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx); |
687 | |
688 | return 0; |
689 | } |
690 | |
691 | static void atmel_tdes_cra_exit(struct crypto_tfm *tfm) |
692 | { |
693 | } |
694 | |
695 | static struct crypto_alg tdes_algs[] = { |
696 | { |
697 | .cra_name = "ecb(des)", |
698 | .cra_driver_name = "atmel-ecb-des", |
699 | .cra_priority = 100, |
700 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
701 | .cra_blocksize = DES_BLOCK_SIZE, |
702 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
703 | .cra_alignmask = 0, |
704 | .cra_type = &crypto_ablkcipher_type, |
705 | .cra_module = THIS_MODULE, |
706 | .cra_init = atmel_tdes_cra_init, |
707 | .cra_exit = atmel_tdes_cra_exit, |
708 | .cra_u.ablkcipher = { |
709 | .min_keysize = DES_KEY_SIZE, |
710 | .max_keysize = DES_KEY_SIZE, |
711 | .setkey = atmel_des_setkey, |
712 | .encrypt = atmel_tdes_ecb_encrypt, |
713 | .decrypt = atmel_tdes_ecb_decrypt, |
714 | } |
715 | }, |
716 | { |
717 | .cra_name = "cbc(des)", |
718 | .cra_driver_name = "atmel-cbc-des", |
719 | .cra_priority = 100, |
720 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
721 | .cra_blocksize = DES_BLOCK_SIZE, |
722 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
723 | .cra_alignmask = 0, |
724 | .cra_type = &crypto_ablkcipher_type, |
725 | .cra_module = THIS_MODULE, |
726 | .cra_init = atmel_tdes_cra_init, |
727 | .cra_exit = atmel_tdes_cra_exit, |
728 | .cra_u.ablkcipher = { |
729 | .min_keysize = DES_KEY_SIZE, |
730 | .max_keysize = DES_KEY_SIZE, |
731 | .ivsize = DES_BLOCK_SIZE, |
732 | .setkey = atmel_des_setkey, |
733 | .encrypt = atmel_tdes_cbc_encrypt, |
734 | .decrypt = atmel_tdes_cbc_decrypt, |
735 | } |
736 | }, |
737 | { |
738 | .cra_name = "cfb(des)", |
739 | .cra_driver_name = "atmel-cfb-des", |
740 | .cra_priority = 100, |
741 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
742 | .cra_blocksize = DES_BLOCK_SIZE, |
743 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
744 | .cra_alignmask = 0, |
745 | .cra_type = &crypto_ablkcipher_type, |
746 | .cra_module = THIS_MODULE, |
747 | .cra_init = atmel_tdes_cra_init, |
748 | .cra_exit = atmel_tdes_cra_exit, |
749 | .cra_u.ablkcipher = { |
750 | .min_keysize = DES_KEY_SIZE, |
751 | .max_keysize = DES_KEY_SIZE, |
752 | .ivsize = DES_BLOCK_SIZE, |
753 | .setkey = atmel_des_setkey, |
754 | .encrypt = atmel_tdes_cfb_encrypt, |
755 | .decrypt = atmel_tdes_cfb_decrypt, |
756 | } |
757 | }, |
758 | { |
759 | .cra_name = "cfb8(des)", |
760 | .cra_driver_name = "atmel-cfb8-des", |
761 | .cra_priority = 100, |
762 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
763 | .cra_blocksize = CFB8_BLOCK_SIZE, |
764 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
765 | .cra_alignmask = 0, |
766 | .cra_type = &crypto_ablkcipher_type, |
767 | .cra_module = THIS_MODULE, |
768 | .cra_init = atmel_tdes_cra_init, |
769 | .cra_exit = atmel_tdes_cra_exit, |
770 | .cra_u.ablkcipher = { |
771 | .min_keysize = DES_KEY_SIZE, |
772 | .max_keysize = DES_KEY_SIZE, |
773 | .ivsize = DES_BLOCK_SIZE, |
774 | .setkey = atmel_des_setkey, |
775 | .encrypt = atmel_tdes_cfb8_encrypt, |
776 | .decrypt = atmel_tdes_cfb8_decrypt, |
777 | } |
778 | }, |
779 | { |
780 | .cra_name = "cfb16(des)", |
781 | .cra_driver_name = "atmel-cfb16-des", |
782 | .cra_priority = 100, |
783 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
784 | .cra_blocksize = CFB16_BLOCK_SIZE, |
785 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
786 | .cra_alignmask = 0, |
787 | .cra_type = &crypto_ablkcipher_type, |
788 | .cra_module = THIS_MODULE, |
789 | .cra_init = atmel_tdes_cra_init, |
790 | .cra_exit = atmel_tdes_cra_exit, |
791 | .cra_u.ablkcipher = { |
792 | .min_keysize = DES_KEY_SIZE, |
793 | .max_keysize = DES_KEY_SIZE, |
794 | .ivsize = DES_BLOCK_SIZE, |
795 | .setkey = atmel_des_setkey, |
796 | .encrypt = atmel_tdes_cfb16_encrypt, |
797 | .decrypt = atmel_tdes_cfb16_decrypt, |
798 | } |
799 | }, |
800 | { |
801 | .cra_name = "cfb32(des)", |
802 | .cra_driver_name = "atmel-cfb32-des", |
803 | .cra_priority = 100, |
804 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
805 | .cra_blocksize = CFB32_BLOCK_SIZE, |
806 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
807 | .cra_alignmask = 0, |
808 | .cra_type = &crypto_ablkcipher_type, |
809 | .cra_module = THIS_MODULE, |
810 | .cra_init = atmel_tdes_cra_init, |
811 | .cra_exit = atmel_tdes_cra_exit, |
812 | .cra_u.ablkcipher = { |
813 | .min_keysize = DES_KEY_SIZE, |
814 | .max_keysize = DES_KEY_SIZE, |
815 | .ivsize = DES_BLOCK_SIZE, |
816 | .setkey = atmel_des_setkey, |
817 | .encrypt = atmel_tdes_cfb32_encrypt, |
818 | .decrypt = atmel_tdes_cfb32_decrypt, |
819 | } |
820 | }, |
821 | { |
822 | .cra_name = "ofb(des)", |
823 | .cra_driver_name = "atmel-ofb-des", |
824 | .cra_priority = 100, |
825 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
826 | .cra_blocksize = DES_BLOCK_SIZE, |
827 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
828 | .cra_alignmask = 0, |
829 | .cra_type = &crypto_ablkcipher_type, |
830 | .cra_module = THIS_MODULE, |
831 | .cra_init = atmel_tdes_cra_init, |
832 | .cra_exit = atmel_tdes_cra_exit, |
833 | .cra_u.ablkcipher = { |
834 | .min_keysize = DES_KEY_SIZE, |
835 | .max_keysize = DES_KEY_SIZE, |
836 | .ivsize = DES_BLOCK_SIZE, |
837 | .setkey = atmel_des_setkey, |
838 | .encrypt = atmel_tdes_ofb_encrypt, |
839 | .decrypt = atmel_tdes_ofb_decrypt, |
840 | } |
841 | }, |
842 | { |
843 | .cra_name = "ecb(des3_ede)", |
844 | .cra_driver_name = "atmel-ecb-tdes", |
845 | .cra_priority = 100, |
846 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
847 | .cra_blocksize = DES_BLOCK_SIZE, |
848 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
849 | .cra_alignmask = 0, |
850 | .cra_type = &crypto_ablkcipher_type, |
851 | .cra_module = THIS_MODULE, |
852 | .cra_init = atmel_tdes_cra_init, |
853 | .cra_exit = atmel_tdes_cra_exit, |
854 | .cra_u.ablkcipher = { |
855 | .min_keysize = 2 * DES_KEY_SIZE, |
856 | .max_keysize = 3 * DES_KEY_SIZE, |
857 | .setkey = atmel_tdes_setkey, |
858 | .encrypt = atmel_tdes_ecb_encrypt, |
859 | .decrypt = atmel_tdes_ecb_decrypt, |
860 | } |
861 | }, |
862 | { |
863 | .cra_name = "cbc(des3_ede)", |
864 | .cra_driver_name = "atmel-cbc-tdes", |
865 | .cra_priority = 100, |
866 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
867 | .cra_blocksize = DES_BLOCK_SIZE, |
868 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
869 | .cra_alignmask = 0, |
870 | .cra_type = &crypto_ablkcipher_type, |
871 | .cra_module = THIS_MODULE, |
872 | .cra_init = atmel_tdes_cra_init, |
873 | .cra_exit = atmel_tdes_cra_exit, |
874 | .cra_u.ablkcipher = { |
875 | .min_keysize = 2*DES_KEY_SIZE, |
876 | .max_keysize = 3*DES_KEY_SIZE, |
877 | .ivsize = DES_BLOCK_SIZE, |
878 | .setkey = atmel_tdes_setkey, |
879 | .encrypt = atmel_tdes_cbc_encrypt, |
880 | .decrypt = atmel_tdes_cbc_decrypt, |
881 | } |
882 | }, |
883 | { |
884 | .cra_name = "cfb(des3_ede)", |
885 | .cra_driver_name = "atmel-cfb-tdes", |
886 | .cra_priority = 100, |
887 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
888 | .cra_blocksize = DES_BLOCK_SIZE, |
889 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
890 | .cra_alignmask = 0, |
891 | .cra_type = &crypto_ablkcipher_type, |
892 | .cra_module = THIS_MODULE, |
893 | .cra_init = atmel_tdes_cra_init, |
894 | .cra_exit = atmel_tdes_cra_exit, |
895 | .cra_u.ablkcipher = { |
896 | .min_keysize = 2*DES_KEY_SIZE, |
897 | .max_keysize = 2*DES_KEY_SIZE, |
898 | .ivsize = DES_BLOCK_SIZE, |
899 | .setkey = atmel_tdes_setkey, |
900 | .encrypt = atmel_tdes_cfb_encrypt, |
901 | .decrypt = atmel_tdes_cfb_decrypt, |
902 | } |
903 | }, |
904 | { |
905 | .cra_name = "cfb8(des3_ede)", |
906 | .cra_driver_name = "atmel-cfb8-tdes", |
907 | .cra_priority = 100, |
908 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
909 | .cra_blocksize = CFB8_BLOCK_SIZE, |
910 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
911 | .cra_alignmask = 0, |
912 | .cra_type = &crypto_ablkcipher_type, |
913 | .cra_module = THIS_MODULE, |
914 | .cra_init = atmel_tdes_cra_init, |
915 | .cra_exit = atmel_tdes_cra_exit, |
916 | .cra_u.ablkcipher = { |
917 | .min_keysize = 2*DES_KEY_SIZE, |
918 | .max_keysize = 2*DES_KEY_SIZE, |
919 | .ivsize = DES_BLOCK_SIZE, |
920 | .setkey = atmel_tdes_setkey, |
921 | .encrypt = atmel_tdes_cfb8_encrypt, |
922 | .decrypt = atmel_tdes_cfb8_decrypt, |
923 | } |
924 | }, |
925 | { |
926 | .cra_name = "cfb16(des3_ede)", |
927 | .cra_driver_name = "atmel-cfb16-tdes", |
928 | .cra_priority = 100, |
929 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
930 | .cra_blocksize = CFB16_BLOCK_SIZE, |
931 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
932 | .cra_alignmask = 0, |
933 | .cra_type = &crypto_ablkcipher_type, |
934 | .cra_module = THIS_MODULE, |
935 | .cra_init = atmel_tdes_cra_init, |
936 | .cra_exit = atmel_tdes_cra_exit, |
937 | .cra_u.ablkcipher = { |
938 | .min_keysize = 2*DES_KEY_SIZE, |
939 | .max_keysize = 2*DES_KEY_SIZE, |
940 | .ivsize = DES_BLOCK_SIZE, |
941 | .setkey = atmel_tdes_setkey, |
942 | .encrypt = atmel_tdes_cfb16_encrypt, |
943 | .decrypt = atmel_tdes_cfb16_decrypt, |
944 | } |
945 | }, |
946 | { |
947 | .cra_name = "cfb32(des3_ede)", |
948 | .cra_driver_name = "atmel-cfb32-tdes", |
949 | .cra_priority = 100, |
950 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
951 | .cra_blocksize = CFB32_BLOCK_SIZE, |
952 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
953 | .cra_alignmask = 0, |
954 | .cra_type = &crypto_ablkcipher_type, |
955 | .cra_module = THIS_MODULE, |
956 | .cra_init = atmel_tdes_cra_init, |
957 | .cra_exit = atmel_tdes_cra_exit, |
958 | .cra_u.ablkcipher = { |
959 | .min_keysize = 2*DES_KEY_SIZE, |
960 | .max_keysize = 2*DES_KEY_SIZE, |
961 | .ivsize = DES_BLOCK_SIZE, |
962 | .setkey = atmel_tdes_setkey, |
963 | .encrypt = atmel_tdes_cfb32_encrypt, |
964 | .decrypt = atmel_tdes_cfb32_decrypt, |
965 | } |
966 | }, |
967 | { |
968 | .cra_name = "ofb(des3_ede)", |
969 | .cra_driver_name = "atmel-ofb-tdes", |
970 | .cra_priority = 100, |
971 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, |
972 | .cra_blocksize = DES_BLOCK_SIZE, |
973 | .cra_ctxsize = sizeof(struct atmel_tdes_ctx), |
974 | .cra_alignmask = 0, |
975 | .cra_type = &crypto_ablkcipher_type, |
976 | .cra_module = THIS_MODULE, |
977 | .cra_init = atmel_tdes_cra_init, |
978 | .cra_exit = atmel_tdes_cra_exit, |
979 | .cra_u.ablkcipher = { |
980 | .min_keysize = 2*DES_KEY_SIZE, |
981 | .max_keysize = 3*DES_KEY_SIZE, |
982 | .ivsize = DES_BLOCK_SIZE, |
983 | .setkey = atmel_tdes_setkey, |
984 | .encrypt = atmel_tdes_ofb_encrypt, |
985 | .decrypt = atmel_tdes_ofb_decrypt, |
986 | } |
987 | }, |
988 | }; |
989 | |
990 | static void atmel_tdes_queue_task(unsigned long data) |
991 | { |
992 | struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *)data; |
993 | |
994 | atmel_tdes_handle_queue(dd, NULL); |
995 | } |
996 | |
997 | static void atmel_tdes_done_task(unsigned long data) |
998 | { |
999 | struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data; |
1000 | int err; |
1001 | |
1002 | err = atmel_tdes_crypt_dma_stop(dd); |
1003 | |
1004 | err = dd->err ? : err; |
1005 | |
1006 | if (dd->total && !err) { |
1007 | err = atmel_tdes_crypt_dma_start(dd); |
1008 | if (!err) |
1009 | return; |
1010 | } |
1011 | |
1012 | atmel_tdes_finish_req(dd, err); |
1013 | atmel_tdes_handle_queue(dd, NULL); |
1014 | } |
1015 | |
1016 | static irqreturn_t atmel_tdes_irq(int irq, void *dev_id) |
1017 | { |
1018 | struct atmel_tdes_dev *tdes_dd = dev_id; |
1019 | u32 reg; |
1020 | |
1021 | reg = atmel_tdes_read(tdes_dd, TDES_ISR); |
1022 | if (reg & atmel_tdes_read(tdes_dd, TDES_IMR)) { |
1023 | atmel_tdes_write(tdes_dd, TDES_IDR, reg); |
1024 | if (TDES_FLAGS_BUSY & tdes_dd->flags) |
1025 | tasklet_schedule(&tdes_dd->done_task); |
1026 | else |
1027 | dev_warn(tdes_dd->dev, "TDES interrupt when no active requests.\n"); |
1028 | return IRQ_HANDLED; |
1029 | } |
1030 | |
1031 | return IRQ_NONE; |
1032 | } |
1033 | |
1034 | static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd) |
1035 | { |
1036 | int i; |
1037 | |
1038 | for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) |
1039 | crypto_unregister_alg(&tdes_algs[i]); |
1040 | } |
1041 | |
1042 | static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) |
1043 | { |
1044 | int err, i, j; |
1045 | |
1046 | for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { |
1047 | INIT_LIST_HEAD(&tdes_algs[i].cra_list); |
1048 | err = crypto_register_alg(&tdes_algs[i]); |
1049 | if (err) |
1050 | goto err_tdes_algs; |
1051 | } |
1052 | |
1053 | return 0; |
1054 | |
1055 | err_tdes_algs: |
1056 | for (j = 0; j < i; j++) |
1057 | crypto_unregister_alg(&tdes_algs[j]); |
1058 | |
1059 | return err; |
1060 | } |
1061 | |
1062 | static int __devinit atmel_tdes_probe(struct platform_device *pdev) |
1063 | { |
1064 | struct atmel_tdes_dev *tdes_dd; |
1065 | struct device *dev = &pdev->dev; |
1066 | struct resource *tdes_res; |
1067 | unsigned long tdes_phys_size; |
1068 | int err; |
1069 | |
1070 | tdes_dd = kzalloc(sizeof(struct atmel_tdes_dev), GFP_KERNEL); |
1071 | if (tdes_dd == NULL) { |
1072 | dev_err(dev, "unable to alloc data struct.\n"); |
1073 | err = -ENOMEM; |
1074 | goto tdes_dd_err; |
1075 | } |
1076 | |
1077 | tdes_dd->dev = dev; |
1078 | |
1079 | platform_set_drvdata(pdev, tdes_dd); |
1080 | |
1081 | INIT_LIST_HEAD(&tdes_dd->list); |
1082 | |
1083 | tasklet_init(&tdes_dd->done_task, atmel_tdes_done_task, |
1084 | (unsigned long)tdes_dd); |
1085 | tasklet_init(&tdes_dd->queue_task, atmel_tdes_queue_task, |
1086 | (unsigned long)tdes_dd); |
1087 | |
1088 | crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH); |
1089 | |
1090 | tdes_dd->irq = -1; |
1091 | |
1092 | /* Get the base address */ |
1093 | tdes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1094 | if (!tdes_res) { |
1095 | dev_err(dev, "no MEM resource info\n"); |
1096 | err = -ENODEV; |
1097 | goto res_err; |
1098 | } |
1099 | tdes_dd->phys_base = tdes_res->start; |
1100 | tdes_phys_size = resource_size(tdes_res); |
1101 | |
1102 | /* Get the IRQ */ |
1103 | tdes_dd->irq = platform_get_irq(pdev, 0); |
1104 | if (tdes_dd->irq < 0) { |
1105 | dev_err(dev, "no IRQ resource info\n"); |
1106 | err = tdes_dd->irq; |
1107 | goto res_err; |
1108 | } |
1109 | |
1110 | err = request_irq(tdes_dd->irq, atmel_tdes_irq, IRQF_SHARED, |
1111 | "atmel-tdes", tdes_dd); |
1112 | if (err) { |
1113 | dev_err(dev, "unable to request tdes irq.\n"); |
1114 | goto tdes_irq_err; |
1115 | } |
1116 | |
1117 | /* Initializing the clock */ |
1118 | tdes_dd->iclk = clk_get(&pdev->dev, NULL); |
1119 | if (IS_ERR(tdes_dd->iclk)) { |
1120 | dev_err(dev, "clock intialization failed.\n"); |
1121 | err = PTR_ERR(tdes_dd->iclk); |
1122 | goto clk_err; |
1123 | } |
1124 | |
1125 | tdes_dd->io_base = ioremap(tdes_dd->phys_base, tdes_phys_size); |
1126 | if (!tdes_dd->io_base) { |
1127 | dev_err(dev, "can't ioremap\n"); |
1128 | err = -ENOMEM; |
1129 | goto tdes_io_err; |
1130 | } |
1131 | |
1132 | err = atmel_tdes_dma_init(tdes_dd); |
1133 | if (err) |
1134 | goto err_tdes_dma; |
1135 | |
1136 | spin_lock(&atmel_tdes.lock); |
1137 | list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list); |
1138 | spin_unlock(&atmel_tdes.lock); |
1139 | |
1140 | err = atmel_tdes_register_algs(tdes_dd); |
1141 | if (err) |
1142 | goto err_algs; |
1143 | |
1144 | dev_info(dev, "Atmel DES/TDES\n"); |
1145 | |
1146 | return 0; |
1147 | |
1148 | err_algs: |
1149 | spin_lock(&atmel_tdes.lock); |
1150 | list_del(&tdes_dd->list); |
1151 | spin_unlock(&atmel_tdes.lock); |
1152 | atmel_tdes_dma_cleanup(tdes_dd); |
1153 | err_tdes_dma: |
1154 | iounmap(tdes_dd->io_base); |
1155 | tdes_io_err: |
1156 | clk_put(tdes_dd->iclk); |
1157 | clk_err: |
1158 | free_irq(tdes_dd->irq, tdes_dd); |
1159 | tdes_irq_err: |
1160 | res_err: |
1161 | tasklet_kill(&tdes_dd->done_task); |
1162 | tasklet_kill(&tdes_dd->queue_task); |
1163 | kfree(tdes_dd); |
1164 | tdes_dd = NULL; |
1165 | tdes_dd_err: |
1166 | dev_err(dev, "initialization failed.\n"); |
1167 | |
1168 | return err; |
1169 | } |
1170 | |
1171 | static int __devexit atmel_tdes_remove(struct platform_device *pdev) |
1172 | { |
1173 | static struct atmel_tdes_dev *tdes_dd; |
1174 | |
1175 | tdes_dd = platform_get_drvdata(pdev); |
1176 | if (!tdes_dd) |
1177 | return -ENODEV; |
1178 | spin_lock(&atmel_tdes.lock); |
1179 | list_del(&tdes_dd->list); |
1180 | spin_unlock(&atmel_tdes.lock); |
1181 | |
1182 | atmel_tdes_unregister_algs(tdes_dd); |
1183 | |
1184 | tasklet_kill(&tdes_dd->done_task); |
1185 | tasklet_kill(&tdes_dd->queue_task); |
1186 | |
1187 | atmel_tdes_dma_cleanup(tdes_dd); |
1188 | |
1189 | iounmap(tdes_dd->io_base); |
1190 | |
1191 | clk_put(tdes_dd->iclk); |
1192 | |
1193 | if (tdes_dd->irq >= 0) |
1194 | free_irq(tdes_dd->irq, tdes_dd); |
1195 | |
1196 | kfree(tdes_dd); |
1197 | tdes_dd = NULL; |
1198 | |
1199 | return 0; |
1200 | } |
1201 | |
1202 | static struct platform_driver atmel_tdes_driver = { |
1203 | .probe = atmel_tdes_probe, |
1204 | .remove = __devexit_p(atmel_tdes_remove), |
1205 | .driver = { |
1206 | .name = "atmel_tdes", |
1207 | .owner = THIS_MODULE, |
1208 | }, |
1209 | }; |
1210 | |
1211 | module_platform_driver(atmel_tdes_driver); |
1212 | |
1213 | MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support."); |
1214 | MODULE_LICENSE("GPL v2"); |
1215 | MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique"); |
1216 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9