diff options
author | Nicolas Royer <nicolas@eukrea.com> | 2012-07-01 13:19:45 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2012-07-10 23:08:14 -0400 |
commit | 13802005d8f2db244ec1f5d7f6923de8f7a463db (patch) | |
tree | 05126a6de45d44d63df4ba7451695426a8c1e901 /drivers/crypto | |
parent | bd3c7b5c2aba0d806285700848f588ca482094d8 (diff) |
crypto: atmel - add Atmel DES/TDES driver
Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Eric Bénard <eric@eukrea.com>
Tested-by: Eric Bénard <eric@eukrea.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/Kconfig | 16 | ||||
-rw-r--r-- | drivers/crypto/Makefile | 1 | ||||
-rw-r--r-- | drivers/crypto/atmel-tdes-regs.h | 89 | ||||
-rw-r--r-- | drivers/crypto/atmel-tdes.c | 1215 |
4 files changed, 1321 insertions, 0 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index d04eabef1e8c..76d489b8890f 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig | |||
@@ -349,4 +349,20 @@ config CRYPTO_DEV_ATMEL_AES | |||
349 | To compile this driver as a module, choose M here: the module | 349 | To compile this driver as a module, choose M here: the module |
350 | will be called atmel-aes. | 350 | will be called atmel-aes. |
351 | 351 | ||
352 | config CRYPTO_DEV_ATMEL_TDES | ||
353 | tristate "Support for Atmel DES/TDES hw accelerator" | ||
354 | depends on ARCH_AT91 | ||
355 | select CRYPTO_DES | ||
356 | select CRYPTO_CBC | ||
357 | select CRYPTO_ECB | ||
358 | select CRYPTO_ALGAPI | ||
359 | select CRYPTO_BLKCIPHER | ||
360 | help | ||
361 | Some Atmel processors have DES/TDES hw accelerator. | ||
362 | Select this if you want to use the Atmel module for | ||
363 | DES/TDES algorithms. | ||
364 | |||
365 | To compile this driver as a module, choose M here: the module | ||
366 | will be called atmel-tdes. | ||
367 | |||
352 | endif # CRYPTO_HW | 368 | endif # CRYPTO_HW |
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 44a8147c630e..6b8b75f2b8c0 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile | |||
@@ -18,3 +18,4 @@ obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ | |||
18 | obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o | 18 | obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o |
19 | obj-$(CONFIG_CRYPTO_DEV_NX) += nx/ | 19 | obj-$(CONFIG_CRYPTO_DEV_NX) += nx/ |
20 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o | 20 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o |
21 | obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o | ||
diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h new file mode 100644 index 000000000000..5ac2a900d80c --- /dev/null +++ b/drivers/crypto/atmel-tdes-regs.h | |||
@@ -0,0 +1,89 @@ | |||
1 | #ifndef __ATMEL_TDES_REGS_H__ | ||
2 | #define __ATMEL_TDES_REGS_H__ | ||
3 | |||
4 | #define TDES_CR 0x00 | ||
5 | #define TDES_CR_START (1 << 0) | ||
6 | #define TDES_CR_SWRST (1 << 8) | ||
7 | #define TDES_CR_LOADSEED (1 << 16) | ||
8 | |||
9 | #define TDES_MR 0x04 | ||
10 | #define TDES_MR_CYPHER_DEC (0 << 0) | ||
11 | #define TDES_MR_CYPHER_ENC (1 << 0) | ||
12 | #define TDES_MR_TDESMOD_MASK (0x3 << 1) | ||
13 | #define TDES_MR_TDESMOD_DES (0x0 << 1) | ||
14 | #define TDES_MR_TDESMOD_TDES (0x1 << 1) | ||
15 | #define TDES_MR_TDESMOD_XTEA (0x2 << 1) | ||
16 | #define TDES_MR_KEYMOD_3KEY (0 << 4) | ||
17 | #define TDES_MR_KEYMOD_2KEY (1 << 4) | ||
18 | #define TDES_MR_SMOD_MASK (0x3 << 8) | ||
19 | #define TDES_MR_SMOD_MANUAL (0x0 << 8) | ||
20 | #define TDES_MR_SMOD_AUTO (0x1 << 8) | ||
21 | #define TDES_MR_SMOD_PDC (0x2 << 8) | ||
22 | #define TDES_MR_OPMOD_MASK (0x3 << 12) | ||
23 | #define TDES_MR_OPMOD_ECB (0x0 << 12) | ||
24 | #define TDES_MR_OPMOD_CBC (0x1 << 12) | ||
25 | #define TDES_MR_OPMOD_OFB (0x2 << 12) | ||
26 | #define TDES_MR_OPMOD_CFB (0x3 << 12) | ||
27 | #define TDES_MR_LOD (0x1 << 15) | ||
28 | #define TDES_MR_CFBS_MASK (0x3 << 16) | ||
29 | #define TDES_MR_CFBS_64b (0x0 << 16) | ||
30 | #define TDES_MR_CFBS_32b (0x1 << 16) | ||
31 | #define TDES_MR_CFBS_16b (0x2 << 16) | ||
32 | #define TDES_MR_CFBS_8b (0x3 << 16) | ||
33 | #define TDES_MR_CKEY_MASK (0xF << 20) | ||
34 | #define TDES_MR_CKEY_OFFSET 20 | ||
35 | #define TDES_MR_CTYPE_MASK (0x3F << 24) | ||
36 | #define TDES_MR_CTYPE_OFFSET 24 | ||
37 | |||
38 | #define TDES_IER 0x10 | ||
39 | #define TDES_IDR 0x14 | ||
40 | #define TDES_IMR 0x18 | ||
41 | #define TDES_ISR 0x1C | ||
42 | #define TDES_INT_DATARDY (1 << 0) | ||
43 | #define TDES_INT_ENDRX (1 << 1) | ||
44 | #define TDES_INT_ENDTX (1 << 2) | ||
45 | #define TDES_INT_RXBUFF (1 << 3) | ||
46 | #define TDES_INT_TXBUFE (1 << 4) | ||
47 | #define TDES_INT_URAD (1 << 8) | ||
48 | #define TDES_ISR_URAT_MASK (0x3 << 12) | ||
49 | #define TDES_ISR_URAT_IDR (0x0 << 12) | ||
50 | #define TDES_ISR_URAT_ODR (0x1 << 12) | ||
51 | #define TDES_ISR_URAT_MR (0x2 << 12) | ||
52 | #define TDES_ISR_URAT_WO (0x3 << 12) | ||
53 | |||
54 | |||
55 | #define TDES_KEY1W1R 0x20 | ||
56 | #define TDES_KEY1W2R 0x24 | ||
57 | #define TDES_KEY2W1R 0x28 | ||
58 | #define TDES_KEY2W2R 0x2C | ||
59 | #define TDES_KEY3W1R 0x30 | ||
60 | #define TDES_KEY3W2R 0x34 | ||
61 | #define TDES_IDATA1R 0x40 | ||
62 | #define TDES_IDATA2R 0x44 | ||
63 | #define TDES_ODATA1R 0x50 | ||
64 | #define TDES_ODATA2R 0x54 | ||
65 | #define TDES_IV1R 0x60 | ||
66 | #define TDES_IV2R 0x64 | ||
67 | |||
68 | #define TDES_XTEARNDR 0x70 | ||
69 | #define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0) | ||
70 | #define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0 | ||
71 | |||
72 | #define TDES_RPR 0x100 | ||
73 | #define TDES_RCR 0x104 | ||
74 | #define TDES_TPR 0x108 | ||
75 | #define TDES_TCR 0x10C | ||
76 | #define TDES_RNPR 0x118 | ||
77 | #define TDES_RNCR 0x11C | ||
78 | #define TDES_TNPR 0x118 | ||
79 | #define TDES_TNCR 0x11C | ||
80 | #define TDES_PTCR 0x120 | ||
81 | #define TDES_PTCR_RXTEN (1 << 0) | ||
82 | #define TDES_PTCR_RXTDIS (1 << 1) | ||
83 | #define TDES_PTCR_TXTEN (1 << 8) | ||
84 | #define TDES_PTCR_TXTDIS (1 << 9) | ||
85 | #define TDES_PTSR 0x124 | ||
86 | #define TDES_PTSR_RXTEN (1 << 0) | ||
87 | #define TDES_PTSR_TXTEN (1 << 8) | ||
88 | |||
89 | #endif /* __ATMEL_TDES_REGS_H__ */ | ||
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c new file mode 100644 index 000000000000..eb2b61e57e2d --- /dev/null +++ b/drivers/crypto/atmel-tdes.c | |||
@@ -0,0 +1,1215 @@ | |||
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"); | ||