diff options
Diffstat (limited to 'recipes-kernel/linux/linux-am335x-psp-3.2/0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch')
-rw-r--r-- | recipes-kernel/linux/linux-am335x-psp-3.2/0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch | 1444 |
1 files changed, 1444 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-am335x-psp-3.2/0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch b/recipes-kernel/linux/linux-am335x-psp-3.2/0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch new file mode 100644 index 00000000..13c7e9ea --- /dev/null +++ b/recipes-kernel/linux/linux-am335x-psp-3.2/0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch | |||
@@ -0,0 +1,1444 @@ | |||
1 | From 31e5e24a1d713b1f8306050e6b6a640ec30b1848 Mon Sep 17 00:00:00 2001 | ||
2 | From: Greg Turner <gregturner@ti.com> | ||
3 | Date: Thu, 17 May 2012 15:19:26 -0500 | ||
4 | Subject: [PATCH 8/8] am33x: Create driver for SHA/MD5 crypto module | ||
5 | |||
6 | This is the initial version of the SHA/MD5 driver for OMAP4 derivative SOC's such as AM335x. | ||
7 | |||
8 | Signed-off-by: Greg Turner <gregturner@ti.com> | ||
9 | --- | ||
10 | drivers/crypto/omap4-sham.c | 1423 +++++++++++++++++++++++++++++++++++++++++++ | ||
11 | 1 files changed, 1423 insertions(+), 0 deletions(-) | ||
12 | create mode 100755 drivers/crypto/omap4-sham.c | ||
13 | |||
14 | diff --git a/drivers/crypto/omap4-sham.c b/drivers/crypto/omap4-sham.c | ||
15 | new file mode 100755 | ||
16 | index 0000000..79f6be9 | ||
17 | --- /dev/null | ||
18 | +++ b/drivers/crypto/omap4-sham.c | ||
19 | @@ -0,0 +1,1423 @@ | ||
20 | +/* | ||
21 | + * Cryptographic API. | ||
22 | + * | ||
23 | + * Support for OMAP SHA1/MD5 HW acceleration. | ||
24 | + * | ||
25 | + * Copyright (c) 2010 Nokia Corporation | ||
26 | + * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> | ||
27 | + * | ||
28 | + * This program is free software; you can redistribute it and/or modify | ||
29 | + * it under the terms of the GNU General Public License version 2 as published | ||
30 | + * by the Free Software Foundation. | ||
31 | + * | ||
32 | + * Some ideas are from old omap-sha1-md5.c driver. | ||
33 | + */ | ||
34 | +/* | ||
35 | + * Copyright © 2011 Texas Instruments Incorporated | ||
36 | + * Author: Herman Schuurman | ||
37 | + * Change: July 2011 - Adapted the omap-sham.c driver to support Netra | ||
38 | + * implementation of SHA/MD5 hardware accelerator. | ||
39 | + * Dec 2011 - Updated with latest omap-sham.c driver changes. | ||
40 | + */ | ||
41 | + | ||
42 | +//#define DEBUG | ||
43 | + | ||
44 | +#define pr_fmt(fmt) "%s: " fmt, __func__ | ||
45 | + | ||
46 | +#include <linux/err.h> | ||
47 | +#include <linux/device.h> | ||
48 | +#include <linux/module.h> | ||
49 | +#include <linux/init.h> | ||
50 | +#include <linux/errno.h> | ||
51 | +#include <linux/interrupt.h> | ||
52 | +#include <linux/kernel.h> | ||
53 | +#include <linux/clk.h> | ||
54 | +#include <linux/irq.h> | ||
55 | +#include <linux/io.h> | ||
56 | +#include <linux/platform_device.h> | ||
57 | +#include <linux/scatterlist.h> | ||
58 | +#include <linux/dma-mapping.h> | ||
59 | +#include <linux/delay.h> | ||
60 | +#include <linux/crypto.h> | ||
61 | +#include <linux/cryptohash.h> | ||
62 | +#include <crypto/scatterwalk.h> | ||
63 | +#include <crypto/algapi.h> | ||
64 | +#include <crypto/sha.h> | ||
65 | +#include <crypto/md5.h> | ||
66 | +#include <crypto/hash.h> | ||
67 | +#include <crypto/internal/hash.h> | ||
68 | + | ||
69 | +#include <mach/hardware.h> | ||
70 | +#include <plat/cpu.h> | ||
71 | +#include <plat/dma.h> | ||
72 | +#include <mach/edma.h> | ||
73 | +#include <mach/irqs.h> | ||
74 | +#include "omap4.h" | ||
75 | + | ||
76 | +#define SHA2_MD5_BLOCK_SIZE SHA1_BLOCK_SIZE | ||
77 | + | ||
78 | +#define DEFAULT_TIMEOUT_INTERVAL HZ | ||
79 | + | ||
80 | +/* device flags */ | ||
81 | +#define FLAGS_BUSY 0 | ||
82 | +#define FLAGS_FINAL 1 | ||
83 | +#define FLAGS_DMA_ACTIVE 2 | ||
84 | +#define FLAGS_OUTPUT_READY 3 /* shared with context flags */ | ||
85 | +#define FLAGS_INIT 4 | ||
86 | +#define FLAGS_CPU 5 /* shared with context flags */ | ||
87 | +#define FLAGS_DMA_READY 6 /* shared with context flags */ | ||
88 | + | ||
89 | +/* context flags */ | ||
90 | +#define FLAGS_FINUP 16 | ||
91 | +#define FLAGS_SG 17 | ||
92 | +#define FLAGS_MODE_SHIFT 18 | ||
93 | +#define FLAGS_MODE_MASK (SHA_REG_MODE_ALGO_MASK << (FLAGS_MODE_SHIFT - 1)) | ||
94 | +#define FLAGS_MD5 (SHA_REG_MODE_ALGO_MD5_128 << (FLAGS_MODE_SHIFT - 1)) | ||
95 | +#define FLAGS_SHA1 (SHA_REG_MODE_ALGO_SHA1_160 << (FLAGS_MODE_SHIFT - 1)) | ||
96 | +#define FLAGS_SHA224 (SHA_REG_MODE_ALGO_SHA2_224 << (FLAGS_MODE_SHIFT - 1)) | ||
97 | +#define FLAGS_SHA256 (SHA_REG_MODE_ALGO_SHA2_256 << (FLAGS_MODE_SHIFT - 1)) | ||
98 | +#define FLAGS_HMAC 20 | ||
99 | +#define FLAGS_ERROR 21 | ||
100 | + | ||
101 | +#define OP_UPDATE 1 | ||
102 | +#define OP_FINAL 2 | ||
103 | + | ||
104 | +#define AM33X_ALIGN_MASK (sizeof(u32)-1) | ||
105 | +#define AM33X_ALIGNED __attribute__((aligned(sizeof(u32)))) | ||
106 | + | ||
107 | +#define BUFLEN PAGE_SIZE | ||
108 | + | ||
109 | +struct omap4_sham_dev; | ||
110 | + | ||
111 | +struct omap4_sham_reqctx { | ||
112 | + struct omap4_sham_dev *dd; | ||
113 | + unsigned long rflags; | ||
114 | + unsigned long op; | ||
115 | + | ||
116 | + u8 digest[SHA256_DIGEST_SIZE] AM33X_ALIGNED; | ||
117 | + size_t digcnt; /* total digest byte count */ | ||
118 | + size_t bufcnt; /* bytes in buffer */ | ||
119 | + size_t buflen; /* buffer length */ | ||
120 | + dma_addr_t dma_addr; | ||
121 | + | ||
122 | + /* walk state */ | ||
123 | + struct scatterlist *sg; | ||
124 | + unsigned int offset; /* offset in current sg */ | ||
125 | + unsigned int total; /* total request */ | ||
126 | + | ||
127 | + u8 buffer[0] AM33X_ALIGNED; | ||
128 | +}; | ||
129 | + | ||
130 | +/* This structure holds the initial HMAC key value, and subsequently | ||
131 | + * the outer digest in the first 32 bytes. The inner digest will be | ||
132 | + * kept within the request context to conform to hash only | ||
133 | + * computations. | ||
134 | + */ | ||
135 | +struct omap4_sham_hmac_ctx { | ||
136 | + struct crypto_shash *shash; | ||
137 | + u8 keypad[SHA2_MD5_BLOCK_SIZE] AM33X_ALIGNED; | ||
138 | + u32 odigest[SHA256_DIGEST_SIZE / sizeof(u32)]; | ||
139 | +}; | ||
140 | + | ||
141 | +struct omap4_sham_ctx { | ||
142 | + struct omap4_sham_dev *dd; | ||
143 | + | ||
144 | + unsigned long cflags; | ||
145 | + | ||
146 | + /* fallback stuff */ | ||
147 | + struct crypto_shash *fallback; | ||
148 | + | ||
149 | + struct omap4_sham_hmac_ctx base[0]; | ||
150 | +}; | ||
151 | + | ||
152 | +#define AM33X_SHAM_QUEUE_LENGTH 1 | ||
153 | + | ||
154 | +struct omap4_sham_dev { | ||
155 | + struct list_head list; | ||
156 | + unsigned long phys_base; | ||
157 | + struct device *dev; | ||
158 | + void __iomem *io_base; | ||
159 | + int irq; | ||
160 | + struct clk *iclk; | ||
161 | + spinlock_t lock; | ||
162 | + int err; | ||
163 | + int dma; | ||
164 | + int dma_lch; | ||
165 | + struct tasklet_struct done_task; | ||
166 | + | ||
167 | + unsigned long dflags; | ||
168 | + struct crypto_queue queue; | ||
169 | + struct ahash_request *req; | ||
170 | +}; | ||
171 | + | ||
172 | +struct omap4_sham_drv { | ||
173 | + struct list_head dev_list; | ||
174 | + spinlock_t lock; | ||
175 | + unsigned long flags; /* superfluous ???? */ | ||
176 | +}; | ||
177 | + | ||
178 | +static struct omap4_sham_drv sham = { | ||
179 | + .dev_list = LIST_HEAD_INIT(sham.dev_list), | ||
180 | + .lock = __SPIN_LOCK_UNLOCKED(sham.lock), | ||
181 | +}; | ||
182 | + | ||
183 | +static inline u32 omap4_sham_read(struct omap4_sham_dev *dd, u32 offset) | ||
184 | +{ | ||
185 | + return __raw_readl(dd->io_base + offset); | ||
186 | +} | ||
187 | + | ||
188 | +static inline void omap4_sham_write(struct omap4_sham_dev *dd, | ||
189 | + u32 offset, u32 value) | ||
190 | +{ | ||
191 | + __raw_writel(value, dd->io_base + offset); | ||
192 | +} | ||
193 | + | ||
194 | +static inline void omap4_sham_write_mask(struct omap4_sham_dev *dd, u32 address, | ||
195 | + u32 value, u32 mask) | ||
196 | +{ | ||
197 | + u32 val; | ||
198 | + | ||
199 | + val = omap4_sham_read(dd, address); | ||
200 | + val &= ~mask; | ||
201 | + val |= value; | ||
202 | + omap4_sham_write(dd, address, val); | ||
203 | +} | ||
204 | + | ||
205 | +static inline void omap4_sham_write_n(struct omap4_sham_dev *dd, u32 offset, | ||
206 | + u32 *value, int count) | ||
207 | +{ | ||
208 | + for (; count--; value++, offset += 4) | ||
209 | + omap4_sham_write(dd, offset, *value); | ||
210 | +} | ||
211 | + | ||
212 | +static inline int omap4_sham_wait(struct omap4_sham_dev *dd, u32 offset, u32 bit) | ||
213 | +{ | ||
214 | + unsigned long timeout = jiffies + DEFAULT_TIMEOUT_INTERVAL; | ||
215 | + | ||
216 | + while (!(omap4_sham_read(dd, offset) & bit)) { | ||
217 | + if (time_is_before_jiffies(timeout)) | ||
218 | + return -ETIMEDOUT; | ||
219 | + } | ||
220 | + | ||
221 | + return 0; | ||
222 | +} | ||
223 | + | ||
224 | +static void omap4_sham_copy_hash(struct ahash_request *req, int out) | ||
225 | +{ | ||
226 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
227 | + u32 *hash = (u32 *)ctx->digest; | ||
228 | + int i; | ||
229 | + | ||
230 | + if (ctx->rflags & BIT(FLAGS_HMAC)) { | ||
231 | + struct crypto_ahash *tfm = crypto_ahash_reqtfm(ctx->dd->req); | ||
232 | + struct omap4_sham_ctx *tctx = crypto_ahash_ctx(tfm); | ||
233 | + struct omap4_sham_hmac_ctx *bctx = tctx->base; | ||
234 | + | ||
235 | + for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) { | ||
236 | + if (out) | ||
237 | + bctx->odigest[i] = omap4_sham_read(ctx->dd, | ||
238 | + SHA_REG_ODIGEST_N(i)); | ||
239 | + else | ||
240 | + omap4_sham_write(ctx->dd, | ||
241 | + SHA_REG_ODIGEST_N(i), bctx->odigest[i]); | ||
242 | + } | ||
243 | + } | ||
244 | + | ||
245 | + /* Copy sha256 size to reduce code */ | ||
246 | + for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) { | ||
247 | + if (out) | ||
248 | + hash[i] = omap4_sham_read(ctx->dd, | ||
249 | + SHA_REG_IDIGEST_N(i)); | ||
250 | + else | ||
251 | + omap4_sham_write(ctx->dd, | ||
252 | + SHA_REG_IDIGEST_N(i), hash[i]); | ||
253 | + } | ||
254 | +} | ||
255 | + | ||
256 | +static void omap4_sham_copy_ready_hash(struct ahash_request *req) | ||
257 | +{ | ||
258 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
259 | + u32 *in = (u32 *)ctx->digest; | ||
260 | + u32 *hash = (u32 *)req->result; | ||
261 | + int i, d; | ||
262 | + | ||
263 | + if (!hash) | ||
264 | + return; | ||
265 | + | ||
266 | + switch (ctx->rflags & FLAGS_MODE_MASK) { | ||
267 | + case FLAGS_MD5: | ||
268 | + d = MD5_DIGEST_SIZE / sizeof(u32); | ||
269 | + break; | ||
270 | + case FLAGS_SHA1: | ||
271 | + d = SHA1_DIGEST_SIZE / sizeof(u32); | ||
272 | + break; | ||
273 | + case FLAGS_SHA224: | ||
274 | + d = SHA224_DIGEST_SIZE / sizeof(u32); | ||
275 | + break; | ||
276 | + case FLAGS_SHA256: | ||
277 | + d = SHA256_DIGEST_SIZE / sizeof(u32); | ||
278 | + break; | ||
279 | + } | ||
280 | + | ||
281 | + /* all results are in little endian */ | ||
282 | + for (i = 0; i < d; i++) | ||
283 | + hash[i] = le32_to_cpu(in[i]); | ||
284 | +} | ||
285 | + | ||
286 | +#if 0 | ||
287 | +static int omap4_sham_hw_init(struct omap4_sham_dev *dd) | ||
288 | +{ | ||
289 | + omap4_sham_write(dd, SHA_REG_SYSCFG, SHA_REG_SYSCFG_SOFTRESET); | ||
290 | + /* | ||
291 | + * prevent OCP bus error (SRESP) in case an access to the module | ||
292 | + * is performed while the module is coming out of soft reset | ||
293 | + */ | ||
294 | + __asm__ __volatile__("nop"); | ||
295 | + __asm__ __volatile__("nop"); | ||
296 | + | ||
297 | + if (omap4_sham_wait(dd, SHA_REG_SYSSTATUS, SHA_REG_SYSSTATUS_RESETDONE)) | ||
298 | + return -ETIMEDOUT; | ||
299 | + | ||
300 | + omap4_sham_write(dd, SHA_REG_SYSCFG, | ||
301 | + SHA_REG_SYSCFG_SIDLE_SMARTIDLE | SHA_REG_SYSCFG_AUTOIDLE); | ||
302 | + set_bit(FLAGS_INIT, &dd->dflags); | ||
303 | + dd->err = 0; | ||
304 | + | ||
305 | + return 0; | ||
306 | +} | ||
307 | +#endif | ||
308 | + | ||
309 | +static void omap4_sham_write_ctrl(struct omap4_sham_dev *dd, int final, int dma) | ||
310 | +{ | ||
311 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
312 | + u32 val, mask; | ||
313 | + | ||
314 | + /* | ||
315 | + * Setting ALGO_CONST only for the first iteration and | ||
316 | + * CLOSE_HASH only for the last one. Note that flags mode bits | ||
317 | + * correspond to algorithm encoding in mode register. | ||
318 | + */ | ||
319 | + val = (ctx->rflags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT - 1); | ||
320 | + if (!ctx->digcnt) { | ||
321 | + struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req); | ||
322 | + struct omap4_sham_ctx *tctx = crypto_ahash_ctx(tfm); | ||
323 | + struct omap4_sham_hmac_ctx *bctx = tctx->base; | ||
324 | + | ||
325 | + val |= SHA_REG_MODE_ALGO_CONSTANT; | ||
326 | + if (ctx->rflags & BIT(FLAGS_HMAC)) { | ||
327 | + val |= SHA_REG_MODE_HMAC_KEY_PROC; | ||
328 | + omap4_sham_write_n(dd, SHA_REG_ODIGEST, (u32 *) bctx->keypad, | ||
329 | + SHA2_MD5_BLOCK_SIZE / sizeof(u32)); | ||
330 | + ctx->digcnt += SHA2_MD5_BLOCK_SIZE; | ||
331 | + } | ||
332 | + } | ||
333 | + if (final) { | ||
334 | + val |= SHA_REG_MODE_CLOSE_HASH; | ||
335 | + | ||
336 | + if (ctx->rflags & BIT(FLAGS_HMAC)) { | ||
337 | + val |= SHA_REG_MODE_HMAC_OUTER_HASH; | ||
338 | + } | ||
339 | + } | ||
340 | + | ||
341 | + mask = SHA_REG_MODE_ALGO_CONSTANT | SHA_REG_MODE_CLOSE_HASH | | ||
342 | + SHA_REG_MODE_ALGO_MASK | SHA_REG_MODE_HMAC_OUTER_HASH | | ||
343 | + SHA_REG_MODE_HMAC_KEY_PROC; | ||
344 | + | ||
345 | + dev_dbg(dd->dev, "ctrl: %08x, flags: %08lx\n", val, ctx->rflags); | ||
346 | + omap4_sham_write_mask(dd, SHA_REG_MODE, val, mask); | ||
347 | + omap4_sham_write(dd, SHA_REG_IRQENA, SHA_REG_IRQENA_OUTPUT_RDY); | ||
348 | + omap4_sham_write_mask(dd, SHA_REG_SYSCFG, | ||
349 | + SHA_REG_SYSCFG_SIT_EN | (dma ? SHA_REG_SYSCFG_SDMA_EN : 0), | ||
350 | + SHA_REG_SYSCFG_SIT_EN | SHA_REG_SYSCFG_SDMA_EN); | ||
351 | +} | ||
352 | + | ||
353 | +static int omap4_sham_xmit_cpu(struct omap4_sham_dev *dd, const u8 *buf, | ||
354 | + size_t length, int final) | ||
355 | +{ | ||
356 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
357 | + int count, len32; | ||
358 | + const u32 *buffer = (const u32 *)buf; | ||
359 | + | ||
360 | + dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n", | ||
361 | + ctx->digcnt, length, final); | ||
362 | + | ||
363 | + if (final) | ||
364 | + set_bit(FLAGS_FINAL, &dd->dflags); /* catch last interrupt */ | ||
365 | + | ||
366 | + set_bit(FLAGS_CPU, &dd->dflags); | ||
367 | + | ||
368 | + omap4_sham_write_ctrl(dd, final, 0); | ||
369 | + /* | ||
370 | + * Setting the length field will also trigger start of | ||
371 | + * processing. | ||
372 | + */ | ||
373 | + omap4_sham_write(dd, SHA_REG_LENGTH, length); | ||
374 | + | ||
375 | + /* short-circuit zero length */ | ||
376 | + if (likely(length)) { | ||
377 | + ctx->digcnt += length; | ||
378 | + | ||
379 | + if (omap4_sham_wait(dd, SHA_REG_IRQSTATUS, SHA_REG_IRQSTATUS_INPUT_RDY)) | ||
380 | + return -ETIMEDOUT; | ||
381 | + | ||
382 | + len32 = DIV_ROUND_UP(length, sizeof(u32)); | ||
383 | + | ||
384 | + for (count = 0; count < len32; count++) | ||
385 | + omap4_sham_write(dd, SHA_REG_DATA_N(count), buffer[count]); | ||
386 | + } | ||
387 | + | ||
388 | + return -EINPROGRESS; | ||
389 | +} | ||
390 | + | ||
391 | +static int omap4_sham_xmit_dma(struct omap4_sham_dev *dd, dma_addr_t dma_addr, | ||
392 | + size_t length, int final) | ||
393 | +{ | ||
394 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
395 | + int nblocks; | ||
396 | + struct edmacc_param p_ram; | ||
397 | + | ||
398 | + dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n", | ||
399 | + ctx->digcnt, length, final); | ||
400 | + | ||
401 | + nblocks = DIV_ROUND_UP(length, SHA2_MD5_BLOCK_SIZE); | ||
402 | + | ||
403 | + /* EDMA IN */ | ||
404 | + p_ram.opt = TCINTEN | | ||
405 | + EDMA_TCC(EDMA_CHAN_SLOT(dd->dma_lch)); | ||
406 | + p_ram.src = dma_addr; | ||
407 | + p_ram.a_b_cnt = SHA2_MD5_BLOCK_SIZE | nblocks << 16; | ||
408 | + p_ram.dst = dd->phys_base + SHA_REG_DATA; | ||
409 | + p_ram.src_dst_bidx = SHA2_MD5_BLOCK_SIZE; | ||
410 | + p_ram.link_bcntrld = 1 << 16 | 0xFFFF; | ||
411 | + p_ram.src_dst_cidx = 0; | ||
412 | + p_ram.ccnt = 1; | ||
413 | + edma_write_slot(dd->dma_lch, &p_ram); | ||
414 | + | ||
415 | + omap4_sham_write_ctrl(dd, final, 1); | ||
416 | + | ||
417 | + ctx->digcnt += length; | ||
418 | + | ||
419 | + if (final) | ||
420 | + set_bit(FLAGS_FINAL, &dd->dflags); /* catch last interrupt */ | ||
421 | + | ||
422 | + set_bit(FLAGS_DMA_ACTIVE, &dd->dflags); | ||
423 | + | ||
424 | + edma_start(dd->dma_lch); | ||
425 | + | ||
426 | + /* | ||
427 | + * Setting the length field will also trigger start of | ||
428 | + * processing. | ||
429 | + */ | ||
430 | + omap4_sham_write(dd, SHA_REG_LENGTH, length); | ||
431 | + | ||
432 | + return -EINPROGRESS; | ||
433 | +} | ||
434 | + | ||
435 | +static size_t omap4_sham_append_buffer(struct omap4_sham_reqctx *ctx, | ||
436 | + const u8 *data, size_t length) | ||
437 | +{ | ||
438 | + size_t count = min(length, ctx->buflen - ctx->bufcnt); | ||
439 | + | ||
440 | + count = min(count, ctx->total); | ||
441 | + if (count <= 0) | ||
442 | + return 0; | ||
443 | + memcpy(ctx->buffer + ctx->bufcnt, data, count); | ||
444 | + ctx->bufcnt += count; | ||
445 | + | ||
446 | + return count; | ||
447 | +} | ||
448 | + | ||
449 | +static size_t omap4_sham_append_sg(struct omap4_sham_reqctx *ctx) | ||
450 | +{ | ||
451 | + size_t count; | ||
452 | + | ||
453 | + while (ctx->sg) { | ||
454 | + if (ctx->sg->length) { | ||
455 | + count = omap4_sham_append_buffer(ctx, | ||
456 | + sg_virt(ctx->sg) + ctx->offset, | ||
457 | + ctx->sg->length - ctx->offset); | ||
458 | + if (!count) | ||
459 | + break; | ||
460 | + ctx->offset += count; | ||
461 | + ctx->total -= count; | ||
462 | + } | ||
463 | + if (ctx->offset == ctx->sg->length) { | ||
464 | + ctx->sg = sg_next(ctx->sg); | ||
465 | + if (ctx->sg) | ||
466 | + ctx->offset = 0; | ||
467 | + else | ||
468 | + ctx->total = 0; | ||
469 | + } | ||
470 | + } | ||
471 | + | ||
472 | + return 0; | ||
473 | +} | ||
474 | + | ||
475 | +static int omap4_sham_xmit_dma_map(struct omap4_sham_dev *dd, | ||
476 | + struct omap4_sham_reqctx *ctx, | ||
477 | + size_t length, int final) | ||
478 | +{ | ||
479 | + ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen, | ||
480 | + DMA_TO_DEVICE); | ||
481 | + if (dma_mapping_error(dd->dev, ctx->dma_addr)) { | ||
482 | + dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen); | ||
483 | + return -EINVAL; | ||
484 | + } | ||
485 | + | ||
486 | + ctx->rflags &= ~BIT(FLAGS_SG); | ||
487 | + | ||
488 | + /* next call does not fail... so no unmap in the case of error */ | ||
489 | + return omap4_sham_xmit_dma(dd, ctx->dma_addr, length, final); | ||
490 | +} | ||
491 | + | ||
492 | +static int omap4_sham_update_dma_slow(struct omap4_sham_dev *dd) | ||
493 | +{ | ||
494 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
495 | + unsigned int final; | ||
496 | + size_t count; | ||
497 | + | ||
498 | + omap4_sham_append_sg(ctx); | ||
499 | + | ||
500 | + final = (ctx->rflags & BIT(FLAGS_FINUP)) && !ctx->total; | ||
501 | + | ||
502 | + dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n", | ||
503 | + ctx->bufcnt, ctx->digcnt, final); | ||
504 | + | ||
505 | + if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) { | ||
506 | + count = ctx->bufcnt; | ||
507 | + ctx->bufcnt = 0; | ||
508 | + return omap4_sham_xmit_dma_map(dd, ctx, count, final); | ||
509 | + } | ||
510 | + | ||
511 | + return 0; | ||
512 | +} | ||
513 | + | ||
514 | +/* Start address alignment */ | ||
515 | +#define SG_AA(sg) (IS_ALIGNED(sg->offset, sizeof(u32))) | ||
516 | +/* SHA1 block size alignment */ | ||
517 | +#define SG_SA(sg) (IS_ALIGNED(sg->length, SHA2_MD5_BLOCK_SIZE)) | ||
518 | + | ||
519 | +static int omap4_sham_update_dma_start(struct omap4_sham_dev *dd) | ||
520 | +{ | ||
521 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
522 | + unsigned int length, final, tail; | ||
523 | + struct scatterlist *sg; | ||
524 | + | ||
525 | + if (!ctx->total) | ||
526 | + return 0; | ||
527 | + | ||
528 | + if (ctx->bufcnt || ctx->offset) | ||
529 | + return omap4_sham_update_dma_slow(dd); | ||
530 | + | ||
531 | + dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n", | ||
532 | + ctx->digcnt, ctx->bufcnt, ctx->total); | ||
533 | + | ||
534 | + sg = ctx->sg; | ||
535 | + | ||
536 | + if (!SG_AA(sg)) | ||
537 | + return omap4_sham_update_dma_slow(dd); | ||
538 | + | ||
539 | + if (!sg_is_last(sg) && !SG_SA(sg)) | ||
540 | + /* size is not SHA1_BLOCK_SIZE aligned */ | ||
541 | + return omap4_sham_update_dma_slow(dd); | ||
542 | + | ||
543 | + length = min(ctx->total, sg->length); | ||
544 | + | ||
545 | + if (sg_is_last(sg)) { | ||
546 | + if (!(ctx->rflags & BIT(FLAGS_FINUP))) { | ||
547 | + /* not last sg must be SHA2_MD5_BLOCK_SIZE aligned */ | ||
548 | + tail = length & (SHA2_MD5_BLOCK_SIZE - 1); | ||
549 | + /* without finup() we need one block to close hash */ | ||
550 | + if (!tail) | ||
551 | + tail = SHA2_MD5_BLOCK_SIZE; | ||
552 | + length -= tail; | ||
553 | + } | ||
554 | + } | ||
555 | + | ||
556 | + if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) { | ||
557 | + dev_err(dd->dev, "dma_map_sg error\n"); | ||
558 | + return -EINVAL; | ||
559 | + } | ||
560 | + | ||
561 | + ctx->rflags |= BIT(FLAGS_SG); | ||
562 | + | ||
563 | + ctx->total -= length; | ||
564 | + ctx->offset = length; /* offset where to start slow */ | ||
565 | + | ||
566 | + final = (ctx->rflags & BIT(FLAGS_FINUP)) && !ctx->total; | ||
567 | + | ||
568 | + /* next call does not fail... so no unmap in the case of error */ | ||
569 | + return omap4_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final); | ||
570 | +} | ||
571 | + | ||
572 | +static int omap4_sham_update_cpu(struct omap4_sham_dev *dd) | ||
573 | +{ | ||
574 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
575 | + int bufcnt; | ||
576 | + | ||
577 | + omap4_sham_append_sg(ctx); | ||
578 | + bufcnt = ctx->bufcnt; | ||
579 | + ctx->bufcnt = 0; | ||
580 | + | ||
581 | + return omap4_sham_xmit_cpu(dd, ctx->buffer, bufcnt, 1); | ||
582 | +} | ||
583 | + | ||
584 | +static int omap4_sham_update_dma_stop(struct omap4_sham_dev *dd) | ||
585 | +{ | ||
586 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(dd->req); | ||
587 | + | ||
588 | + edma_stop(dd->dma_lch); | ||
589 | + if (ctx->rflags & BIT(FLAGS_SG)) { | ||
590 | + dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); | ||
591 | + if (ctx->sg->length == ctx->offset) { | ||
592 | + ctx->sg = sg_next(ctx->sg); | ||
593 | + if (ctx->sg) | ||
594 | + ctx->offset = 0; | ||
595 | + } | ||
596 | + } else { | ||
597 | + dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, | ||
598 | + DMA_TO_DEVICE); | ||
599 | + } | ||
600 | + | ||
601 | + return 0; | ||
602 | +} | ||
603 | + | ||
604 | +static int omap4_sham_init(struct ahash_request *req) | ||
605 | +{ | ||
606 | + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
607 | + struct omap4_sham_ctx *tctx = crypto_ahash_ctx(tfm); | ||
608 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
609 | + struct omap4_sham_dev *dd = NULL, *tmp; | ||
610 | + | ||
611 | + spin_lock_bh(&sham.lock); | ||
612 | + if (!tctx->dd) { | ||
613 | + list_for_each_entry(tmp, &sham.dev_list, list) { | ||
614 | + dd = tmp; | ||
615 | + break; | ||
616 | + } | ||
617 | + tctx->dd = dd; | ||
618 | + } else { | ||
619 | + dd = tctx->dd; | ||
620 | + } | ||
621 | + spin_unlock_bh(&sham.lock); | ||
622 | + | ||
623 | + ctx->dd = dd; | ||
624 | + | ||
625 | + ctx->rflags = 0; | ||
626 | + | ||
627 | + dev_dbg(dd->dev, "init: digest size: %d (@0x%08lx)\n", | ||
628 | + crypto_ahash_digestsize(tfm), dd->phys_base); | ||
629 | + | ||
630 | + switch (crypto_ahash_digestsize(tfm)) { | ||
631 | + case MD5_DIGEST_SIZE: | ||
632 | + ctx->rflags |= FLAGS_MD5; | ||
633 | + break; | ||
634 | + case SHA1_DIGEST_SIZE: | ||
635 | + ctx->rflags |= FLAGS_SHA1; | ||
636 | + break; | ||
637 | + case SHA224_DIGEST_SIZE: | ||
638 | + ctx->rflags |= FLAGS_SHA224; | ||
639 | + break; | ||
640 | + case SHA256_DIGEST_SIZE: | ||
641 | + ctx->rflags |= FLAGS_SHA256; | ||
642 | + break; | ||
643 | + } | ||
644 | + | ||
645 | + ctx->bufcnt = 0; | ||
646 | + ctx->digcnt = 0; | ||
647 | + ctx->buflen = BUFLEN; | ||
648 | + | ||
649 | + if (tctx->cflags & BIT(FLAGS_HMAC)) { | ||
650 | + ctx->rflags |= BIT(FLAGS_HMAC); | ||
651 | + } | ||
652 | + | ||
653 | + return 0; | ||
654 | +} | ||
655 | + | ||
656 | +static int omap4_sham_update_req(struct omap4_sham_dev *dd) | ||
657 | +{ | ||
658 | + struct ahash_request *req = dd->req; | ||
659 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
660 | + int err; | ||
661 | + | ||
662 | + dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n", | ||
663 | + ctx->total, ctx->digcnt, (ctx->rflags & BIT(FLAGS_FINUP)) != 0); | ||
664 | + | ||
665 | + if (ctx->rflags & BIT(FLAGS_CPU)) | ||
666 | + err = omap4_sham_update_cpu(dd); | ||
667 | + else | ||
668 | + err = omap4_sham_update_dma_start(dd); | ||
669 | + | ||
670 | + /* wait for dma completion before can take more data */ | ||
671 | + dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt); | ||
672 | + | ||
673 | + return err; | ||
674 | +} | ||
675 | + | ||
676 | +static int omap4_sham_final_req(struct omap4_sham_dev *dd) | ||
677 | +{ | ||
678 | + struct ahash_request *req = dd->req; | ||
679 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
680 | + int err = 0; | ||
681 | + | ||
682 | + if (ctx->bufcnt <= SHA2_MD5_BLOCK_SIZE) /* faster to handle single block with CPU */ | ||
683 | + err = omap4_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1); | ||
684 | + else | ||
685 | + err = omap4_sham_xmit_dma_map(dd, ctx, ctx->bufcnt, 1); | ||
686 | + | ||
687 | + ctx->bufcnt = 0; | ||
688 | + | ||
689 | + dev_dbg(dd->dev, "final_req: err: %d\n", err); | ||
690 | + | ||
691 | + return err; | ||
692 | +} | ||
693 | + | ||
694 | +static int omap4_sham_finish(struct ahash_request *req) | ||
695 | +{ | ||
696 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
697 | + struct omap4_sham_dev *dd = ctx->dd; | ||
698 | + | ||
699 | + omap4_sham_copy_ready_hash(req); | ||
700 | + dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); | ||
701 | + | ||
702 | + return 0; | ||
703 | +} | ||
704 | + | ||
705 | +static void omap4_sham_finish_req(struct ahash_request *req, int err) | ||
706 | +{ | ||
707 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
708 | + struct omap4_sham_dev *dd = ctx->dd; | ||
709 | + | ||
710 | + if (!err) { | ||
711 | + omap4_sham_copy_hash(req, 1); | ||
712 | + if (test_bit(FLAGS_FINAL, &dd->dflags)) { | ||
713 | + err = omap4_sham_finish(req); | ||
714 | + } | ||
715 | + } else { | ||
716 | + ctx->rflags |= BIT(FLAGS_ERROR); | ||
717 | + } | ||
718 | + | ||
719 | + /* atomic operation is not needed here */ | ||
720 | + dd->dflags &= ~(BIT(FLAGS_BUSY) | BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) | | ||
721 | + BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY)); | ||
722 | + clk_disable(dd->iclk); | ||
723 | + | ||
724 | + if (req->base.complete) | ||
725 | + req->base.complete(&req->base, err); | ||
726 | + | ||
727 | + /* handle new request */ | ||
728 | + tasklet_schedule(&dd->done_task); | ||
729 | +} | ||
730 | + | ||
731 | +static int omap4_sham_handle_queue(struct omap4_sham_dev *dd, | ||
732 | + struct ahash_request *req) | ||
733 | +{ | ||
734 | + struct crypto_async_request *async_req, *backlog; | ||
735 | + struct omap4_sham_reqctx *ctx; | ||
736 | + unsigned long flags; | ||
737 | + int err = 0, ret = 0; | ||
738 | + | ||
739 | + spin_lock_irqsave(&dd->lock, flags); | ||
740 | + if (req) | ||
741 | + ret = ahash_enqueue_request(&dd->queue, req); | ||
742 | + if (test_bit(FLAGS_BUSY, &dd->dflags)) { | ||
743 | + spin_unlock_irqrestore(&dd->lock, flags); | ||
744 | + return ret; | ||
745 | + } | ||
746 | + backlog = crypto_get_backlog(&dd->queue); | ||
747 | + async_req = crypto_dequeue_request(&dd->queue); | ||
748 | + if (async_req) | ||
749 | + set_bit(FLAGS_BUSY, &dd->dflags); | ||
750 | + spin_unlock_irqrestore(&dd->lock, flags); | ||
751 | + | ||
752 | + if (!async_req) | ||
753 | + return ret; | ||
754 | + | ||
755 | + if (backlog) | ||
756 | + backlog->complete(backlog, -EINPROGRESS); | ||
757 | + | ||
758 | + req = ahash_request_cast(async_req); | ||
759 | + dd->req = req; | ||
760 | + ctx = ahash_request_ctx(req); | ||
761 | + | ||
762 | + dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", | ||
763 | + ctx->op, req->nbytes); | ||
764 | + | ||
765 | + clk_enable(dd->iclk); | ||
766 | + if (!test_bit(FLAGS_INIT, &dd->dflags)) { | ||
767 | + set_bit(FLAGS_INIT, &dd->dflags); | ||
768 | + dd->err = 0; | ||
769 | + } | ||
770 | + | ||
771 | + if (ctx->digcnt) /* not initial request - restore hash */ | ||
772 | + omap4_sham_copy_hash(req, 0); | ||
773 | + | ||
774 | + if (ctx->op == OP_UPDATE) { | ||
775 | + err = omap4_sham_update_req(dd); | ||
776 | + if (err != -EINPROGRESS && (ctx->rflags & BIT(FLAGS_FINUP))) | ||
777 | + /* no final() after finup() */ | ||
778 | + err = omap4_sham_final_req(dd); | ||
779 | + } else if (ctx->op == OP_FINAL) { | ||
780 | + err = omap4_sham_final_req(dd); | ||
781 | + } | ||
782 | + | ||
783 | + if (err != -EINPROGRESS) | ||
784 | + /* done_task will not finish it, so do it here */ | ||
785 | + omap4_sham_finish_req(req, err); | ||
786 | + | ||
787 | + dev_dbg(dd->dev, "exit, err: %d\n", err); | ||
788 | + | ||
789 | + return ret; | ||
790 | +} | ||
791 | + | ||
792 | +static int omap4_sham_enqueue(struct ahash_request *req, unsigned int op) | ||
793 | +{ | ||
794 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
795 | + struct omap4_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); | ||
796 | + struct omap4_sham_dev *dd = tctx->dd; | ||
797 | + | ||
798 | + ctx->op = op; | ||
799 | + | ||
800 | + return omap4_sham_handle_queue(dd, req); | ||
801 | +} | ||
802 | + | ||
803 | +static int omap4_sham_update(struct ahash_request *req) | ||
804 | +{ | ||
805 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
806 | + | ||
807 | + if (!(ctx->rflags & BIT(FLAGS_FINUP))) | ||
808 | + if (!req->nbytes) | ||
809 | + return 0; | ||
810 | + | ||
811 | + ctx->total = req->nbytes; | ||
812 | + ctx->sg = req->src; | ||
813 | + ctx->offset = 0; | ||
814 | + | ||
815 | + if (ctx->rflags & BIT(FLAGS_FINUP)) { | ||
816 | + if (ctx->bufcnt + ctx->total <= SHA2_MD5_BLOCK_SIZE) { | ||
817 | + /* | ||
818 | + * faster to use CPU for short transfers | ||
819 | + */ | ||
820 | + ctx->rflags |= BIT(FLAGS_CPU); | ||
821 | + } | ||
822 | + } else if (ctx->bufcnt + ctx->total < ctx->buflen) { | ||
823 | + omap4_sham_append_sg(ctx); | ||
824 | + return 0; | ||
825 | + } | ||
826 | + | ||
827 | + return omap4_sham_enqueue(req, OP_UPDATE); | ||
828 | +} | ||
829 | + | ||
830 | +static int omap4_sham_shash_digest(struct crypto_shash *shash, u32 flags, | ||
831 | + const u8 *data, unsigned int len, u8 *out) | ||
832 | +{ | ||
833 | + struct { | ||
834 | + struct shash_desc shash; | ||
835 | + char ctx[crypto_shash_descsize(shash)]; | ||
836 | + } desc; | ||
837 | + | ||
838 | + desc.shash.tfm = shash; | ||
839 | + desc.shash.flags = flags & CRYPTO_TFM_REQ_MAY_SLEEP; | ||
840 | + | ||
841 | + return crypto_shash_digest(&desc.shash, data, len, out); | ||
842 | +} | ||
843 | + | ||
844 | +static int omap4_sham_final(struct ahash_request *req) | ||
845 | +{ | ||
846 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
847 | + | ||
848 | + ctx->rflags |= BIT(FLAGS_FINUP); | ||
849 | + | ||
850 | + if (ctx->rflags & BIT(FLAGS_ERROR)) | ||
851 | + return 0; /* uncompleted hash is not needed */ | ||
852 | + | ||
853 | + return omap4_sham_enqueue(req, OP_FINAL); | ||
854 | +} | ||
855 | + | ||
856 | +static int omap4_sham_finup(struct ahash_request *req) | ||
857 | +{ | ||
858 | + struct omap4_sham_reqctx *ctx = ahash_request_ctx(req); | ||
859 | + int err1, err2; | ||
860 | + | ||
861 | + ctx->rflags |= BIT(FLAGS_FINUP); | ||
862 | + | ||
863 | + err1 = omap4_sham_update(req); | ||
864 | + if (err1 == -EINPROGRESS || err1 == -EBUSY) | ||
865 | + return err1; | ||
866 | + /* | ||
867 | + * final() has to be always called to cleanup resources | ||
868 | + * even if update() failed, except EINPROGRESS | ||
869 | + */ | ||
870 | + err2 = omap4_sham_final(req); | ||
871 | + | ||
872 | + return err1 ?: err2; | ||
873 | +} | ||
874 | + | ||
875 | +static int omap4_sham_digest(struct ahash_request *req) | ||
876 | +{ | ||
877 | + return omap4_sham_init(req) ?: omap4_sham_finup(req); | ||
878 | +} | ||
879 | + | ||
880 | +static int omap4_sham_setkey(struct crypto_ahash *tfm, const u8 *key, | ||
881 | + unsigned int keylen) | ||
882 | +{ | ||
883 | + struct omap4_sham_ctx *tctx = crypto_ahash_ctx(tfm); | ||
884 | + struct omap4_sham_hmac_ctx *bctx = tctx->base; | ||
885 | + int bs = crypto_shash_blocksize(bctx->shash); | ||
886 | + int ds = crypto_shash_digestsize(bctx->shash); | ||
887 | + int err; | ||
888 | + | ||
889 | + /* If key is longer than block size, use hash of original key */ | ||
890 | + if (keylen > bs) { | ||
891 | + err = crypto_shash_setkey(tctx->fallback, key, keylen) ?: | ||
892 | + omap4_sham_shash_digest(bctx->shash, | ||
893 | + crypto_shash_get_flags(bctx->shash), | ||
894 | + key, keylen, bctx->keypad); | ||
895 | + if (err) | ||
896 | + return err; | ||
897 | + keylen = ds; | ||
898 | + } else { | ||
899 | + memcpy(bctx->keypad, key, keylen); | ||
900 | + } | ||
901 | + | ||
902 | + /* zero-pad the key (or its digest) */ | ||
903 | + if (keylen < bs) | ||
904 | + memset(bctx->keypad + keylen, 0, bs - keylen); | ||
905 | + | ||
906 | + return 0; | ||
907 | +} | ||
908 | + | ||
909 | +static int omap4_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) | ||
910 | +{ | ||
911 | + struct omap4_sham_ctx *tctx = crypto_tfm_ctx(tfm); | ||
912 | + const char *alg_name = crypto_tfm_alg_name(tfm); | ||
913 | + | ||
914 | + /* Allocate a fallback and abort if it failed. */ | ||
915 | + tctx->fallback = crypto_alloc_shash(alg_name, 0, | ||
916 | + CRYPTO_ALG_NEED_FALLBACK); | ||
917 | + if (IS_ERR(tctx->fallback)) { | ||
918 | + pr_err("omap4-sham: fallback driver '%s' " | ||
919 | + "could not be loaded.\n", alg_name); | ||
920 | + return PTR_ERR(tctx->fallback); | ||
921 | + } | ||
922 | + | ||
923 | + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), | ||
924 | + sizeof(struct omap4_sham_reqctx) + BUFLEN); | ||
925 | + | ||
926 | + if (alg_base) { | ||
927 | + struct omap4_sham_hmac_ctx *bctx = tctx->base; | ||
928 | + tctx->cflags |= BIT(FLAGS_HMAC); | ||
929 | + bctx->shash = crypto_alloc_shash(alg_base, 0, | ||
930 | + CRYPTO_ALG_NEED_FALLBACK); | ||
931 | + if (IS_ERR(bctx->shash)) { | ||
932 | + pr_err("omap4-sham: base driver '%s' " | ||
933 | + "could not be loaded.\n", alg_base); | ||
934 | + crypto_free_shash(tctx->fallback); | ||
935 | + return PTR_ERR(bctx->shash); | ||
936 | + } | ||
937 | + | ||
938 | + } | ||
939 | + | ||
940 | + return 0; | ||
941 | +} | ||
942 | + | ||
943 | +static int omap4_sham_cra_init(struct crypto_tfm *tfm) | ||
944 | +{ | ||
945 | + return omap4_sham_cra_init_alg(tfm, NULL); | ||
946 | +} | ||
947 | + | ||
948 | +static int omap4_sham_cra_sha1_init(struct crypto_tfm *tfm) | ||
949 | +{ | ||
950 | + return omap4_sham_cra_init_alg(tfm, "sha1"); | ||
951 | +} | ||
952 | + | ||
953 | +static int omap4_sham_cra_sha224_init(struct crypto_tfm *tfm) | ||
954 | +{ | ||
955 | + return omap4_sham_cra_init_alg(tfm, "sha224"); | ||
956 | +} | ||
957 | + | ||
958 | +static int omap4_sham_cra_sha256_init(struct crypto_tfm *tfm) | ||
959 | +{ | ||
960 | + return omap4_sham_cra_init_alg(tfm, "sha256"); | ||
961 | +} | ||
962 | + | ||
963 | +static int omap4_sham_cra_md5_init(struct crypto_tfm *tfm) | ||
964 | +{ | ||
965 | + return omap4_sham_cra_init_alg(tfm, "md5"); | ||
966 | +} | ||
967 | + | ||
968 | +static void omap4_sham_cra_exit(struct crypto_tfm *tfm) | ||
969 | +{ | ||
970 | + struct omap4_sham_ctx *tctx = crypto_tfm_ctx(tfm); | ||
971 | + | ||
972 | + crypto_free_shash(tctx->fallback); | ||
973 | + tctx->fallback = NULL; | ||
974 | + | ||
975 | + if (tctx->cflags & BIT(FLAGS_HMAC)) { | ||
976 | + struct omap4_sham_hmac_ctx *bctx = tctx->base; | ||
977 | + crypto_free_shash(bctx->shash); | ||
978 | + } | ||
979 | +} | ||
980 | + | ||
981 | +static struct ahash_alg algs[] = { | ||
982 | +{ | ||
983 | + .init = omap4_sham_init, | ||
984 | + .update = omap4_sham_update, | ||
985 | + .final = omap4_sham_final, | ||
986 | + .finup = omap4_sham_finup, | ||
987 | + .digest = omap4_sham_digest, | ||
988 | + .halg.digestsize = SHA1_DIGEST_SIZE, | ||
989 | + .halg.base = { | ||
990 | + .cra_name = "sha1", | ||
991 | + .cra_driver_name = "omap4-sha1", | ||
992 | + .cra_priority = 300, | ||
993 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
994 | + CRYPTO_ALG_ASYNC | | ||
995 | + CRYPTO_ALG_NEED_FALLBACK, | ||
996 | + .cra_blocksize = SHA1_BLOCK_SIZE, | ||
997 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx), | ||
998 | + .cra_alignmask = 0, | ||
999 | + .cra_module = THIS_MODULE, | ||
1000 | + .cra_init = omap4_sham_cra_init, | ||
1001 | + .cra_exit = omap4_sham_cra_exit, | ||
1002 | + } | ||
1003 | +}, | ||
1004 | +{ | ||
1005 | + .init = omap4_sham_init, | ||
1006 | + .update = omap4_sham_update, | ||
1007 | + .final = omap4_sham_final, | ||
1008 | + .finup = omap4_sham_finup, | ||
1009 | + .digest = omap4_sham_digest, | ||
1010 | + .halg.digestsize = SHA224_DIGEST_SIZE, | ||
1011 | + .halg.base = { | ||
1012 | + .cra_name = "sha224", | ||
1013 | + .cra_driver_name = "omap4-sha224", | ||
1014 | + .cra_priority = 300, | ||
1015 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1016 | + CRYPTO_ALG_ASYNC | | ||
1017 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1018 | + .cra_blocksize = SHA224_BLOCK_SIZE, | ||
1019 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx), | ||
1020 | + .cra_alignmask = 0, | ||
1021 | + .cra_module = THIS_MODULE, | ||
1022 | + .cra_init = omap4_sham_cra_init, | ||
1023 | + .cra_exit = omap4_sham_cra_exit, | ||
1024 | + } | ||
1025 | +}, | ||
1026 | +{ | ||
1027 | + .init = omap4_sham_init, | ||
1028 | + .update = omap4_sham_update, | ||
1029 | + .final = omap4_sham_final, | ||
1030 | + .finup = omap4_sham_finup, | ||
1031 | + .digest = omap4_sham_digest, | ||
1032 | + .halg.digestsize = SHA256_DIGEST_SIZE, | ||
1033 | + .halg.base = { | ||
1034 | + .cra_name = "sha256", | ||
1035 | + .cra_driver_name = "omap4-sha256", | ||
1036 | + .cra_priority = 300, | ||
1037 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1038 | + CRYPTO_ALG_ASYNC | | ||
1039 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1040 | + .cra_blocksize = SHA256_BLOCK_SIZE, | ||
1041 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx), | ||
1042 | + .cra_alignmask = 0, | ||
1043 | + .cra_module = THIS_MODULE, | ||
1044 | + .cra_init = omap4_sham_cra_init, | ||
1045 | + .cra_exit = omap4_sham_cra_exit, | ||
1046 | + } | ||
1047 | +}, | ||
1048 | +{ | ||
1049 | + .init = omap4_sham_init, | ||
1050 | + .update = omap4_sham_update, | ||
1051 | + .final = omap4_sham_final, | ||
1052 | + .finup = omap4_sham_finup, | ||
1053 | + .digest = omap4_sham_digest, | ||
1054 | + .halg.digestsize = MD5_DIGEST_SIZE, | ||
1055 | + .halg.base = { | ||
1056 | + .cra_name = "md5", | ||
1057 | + .cra_driver_name = "omap4-md5", | ||
1058 | + .cra_priority = 300, | ||
1059 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1060 | + CRYPTO_ALG_ASYNC | | ||
1061 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1062 | + .cra_blocksize = SHA1_BLOCK_SIZE, | ||
1063 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx), | ||
1064 | + .cra_alignmask = AM33X_ALIGN_MASK, | ||
1065 | + .cra_module = THIS_MODULE, | ||
1066 | + .cra_init = omap4_sham_cra_init, | ||
1067 | + .cra_exit = omap4_sham_cra_exit, | ||
1068 | + } | ||
1069 | +}, | ||
1070 | +{ | ||
1071 | + .init = omap4_sham_init, | ||
1072 | + .update = omap4_sham_update, | ||
1073 | + .final = omap4_sham_final, | ||
1074 | + .finup = omap4_sham_finup, | ||
1075 | + .digest = omap4_sham_digest, | ||
1076 | + .setkey = omap4_sham_setkey, | ||
1077 | + .halg.digestsize = SHA1_DIGEST_SIZE, | ||
1078 | + .halg.base = { | ||
1079 | + .cra_name = "hmac(sha1)", | ||
1080 | + .cra_driver_name = "omap4-hmac-sha1", | ||
1081 | + .cra_priority = 300, | ||
1082 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1083 | + CRYPTO_ALG_ASYNC | | ||
1084 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1085 | + .cra_blocksize = SHA1_BLOCK_SIZE, | ||
1086 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx) + | ||
1087 | + sizeof(struct omap4_sham_hmac_ctx), | ||
1088 | + .cra_alignmask = AM33X_ALIGN_MASK, | ||
1089 | + .cra_module = THIS_MODULE, | ||
1090 | + .cra_init = omap4_sham_cra_sha1_init, | ||
1091 | + .cra_exit = omap4_sham_cra_exit, | ||
1092 | + } | ||
1093 | +}, | ||
1094 | +{ | ||
1095 | + .init = omap4_sham_init, | ||
1096 | + .update = omap4_sham_update, | ||
1097 | + .final = omap4_sham_final, | ||
1098 | + .finup = omap4_sham_finup, | ||
1099 | + .digest = omap4_sham_digest, | ||
1100 | + .setkey = omap4_sham_setkey, | ||
1101 | + .halg.digestsize = SHA224_DIGEST_SIZE, | ||
1102 | + .halg.base = { | ||
1103 | + .cra_name = "hmac(sha224)", | ||
1104 | + .cra_driver_name = "omap4-hmac-sha224", | ||
1105 | + .cra_priority = 300, | ||
1106 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1107 | + CRYPTO_ALG_ASYNC | | ||
1108 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1109 | + .cra_blocksize = SHA224_BLOCK_SIZE, | ||
1110 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx) + | ||
1111 | + sizeof(struct omap4_sham_hmac_ctx), | ||
1112 | + .cra_alignmask = AM33X_ALIGN_MASK, | ||
1113 | + .cra_module = THIS_MODULE, | ||
1114 | + .cra_init = omap4_sham_cra_sha224_init, | ||
1115 | + .cra_exit = omap4_sham_cra_exit, | ||
1116 | + } | ||
1117 | +}, | ||
1118 | +{ | ||
1119 | + .init = omap4_sham_init, | ||
1120 | + .update = omap4_sham_update, | ||
1121 | + .final = omap4_sham_final, | ||
1122 | + .finup = omap4_sham_finup, | ||
1123 | + .digest = omap4_sham_digest, | ||
1124 | + .setkey = omap4_sham_setkey, | ||
1125 | + .halg.digestsize = SHA256_DIGEST_SIZE, | ||
1126 | + .halg.base = { | ||
1127 | + .cra_name = "hmac(sha256)", | ||
1128 | + .cra_driver_name = "omap4-hmac-sha256", | ||
1129 | + .cra_priority = 300, | ||
1130 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1131 | + CRYPTO_ALG_ASYNC | | ||
1132 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1133 | + .cra_blocksize = SHA256_BLOCK_SIZE, | ||
1134 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx) + | ||
1135 | + sizeof(struct omap4_sham_hmac_ctx), | ||
1136 | + .cra_alignmask = AM33X_ALIGN_MASK, | ||
1137 | + .cra_module = THIS_MODULE, | ||
1138 | + .cra_init = omap4_sham_cra_sha256_init, | ||
1139 | + .cra_exit = omap4_sham_cra_exit, | ||
1140 | + } | ||
1141 | +}, | ||
1142 | +{ | ||
1143 | + .init = omap4_sham_init, | ||
1144 | + .update = omap4_sham_update, | ||
1145 | + .final = omap4_sham_final, | ||
1146 | + .finup = omap4_sham_finup, | ||
1147 | + .digest = omap4_sham_digest, | ||
1148 | + .setkey = omap4_sham_setkey, | ||
1149 | + .halg.digestsize = MD5_DIGEST_SIZE, | ||
1150 | + .halg.base = { | ||
1151 | + .cra_name = "hmac(md5)", | ||
1152 | + .cra_driver_name = "omap4-hmac-md5", | ||
1153 | + .cra_priority = 300, | ||
1154 | + .cra_flags = CRYPTO_ALG_TYPE_AHASH | | ||
1155 | + CRYPTO_ALG_ASYNC | | ||
1156 | + CRYPTO_ALG_NEED_FALLBACK, | ||
1157 | + .cra_blocksize = SHA1_BLOCK_SIZE, | ||
1158 | + .cra_ctxsize = sizeof(struct omap4_sham_ctx) + | ||
1159 | + sizeof(struct omap4_sham_hmac_ctx), | ||
1160 | + .cra_alignmask = AM33X_ALIGN_MASK, | ||
1161 | + .cra_module = THIS_MODULE, | ||
1162 | + .cra_init = omap4_sham_cra_md5_init, | ||
1163 | + .cra_exit = omap4_sham_cra_exit, | ||
1164 | + } | ||
1165 | +} | ||
1166 | +}; | ||
1167 | + | ||
1168 | +static void omap4_sham_done_task(unsigned long data) | ||
1169 | +{ | ||
1170 | + struct omap4_sham_dev *dd = (struct omap4_sham_dev *)data; | ||
1171 | + int err = 0; | ||
1172 | + | ||
1173 | + if (!test_bit(FLAGS_BUSY, &dd->dflags)) { | ||
1174 | + omap4_sham_handle_queue(dd, NULL); | ||
1175 | + return; | ||
1176 | + } | ||
1177 | + | ||
1178 | + if (test_bit(FLAGS_CPU, &dd->dflags)) { | ||
1179 | + if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->dflags)) | ||
1180 | + goto finish; | ||
1181 | + } else if (test_bit(FLAGS_OUTPUT_READY, &dd->dflags)) { | ||
1182 | + if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->dflags)) { | ||
1183 | + omap4_sham_update_dma_stop(dd); | ||
1184 | + if (dd->err) { | ||
1185 | + err = dd->err; | ||
1186 | + goto finish; | ||
1187 | + } | ||
1188 | + } | ||
1189 | + if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->dflags)) { | ||
1190 | + /* hash or semi-hash ready */ | ||
1191 | + clear_bit(FLAGS_DMA_READY, &dd->dflags); | ||
1192 | + err = omap4_sham_update_dma_start(dd); | ||
1193 | + if (err != -EINPROGRESS) | ||
1194 | + goto finish; | ||
1195 | + } | ||
1196 | + } | ||
1197 | + | ||
1198 | + return; | ||
1199 | + | ||
1200 | +finish: | ||
1201 | + dev_dbg(dd->dev, "update done: err: %d\n", err); | ||
1202 | + /* finish current request */ | ||
1203 | + omap4_sham_finish_req(dd->req, err); | ||
1204 | +} | ||
1205 | + | ||
1206 | +static irqreturn_t omap4_sham_irq(int irq, void *dev_id) | ||
1207 | +{ | ||
1208 | + struct omap4_sham_dev *dd = dev_id; | ||
1209 | + | ||
1210 | +#if 0 | ||
1211 | + if (unlikely(test_bit(FLAGS_FINAL, &dd->flags))) | ||
1212 | + /* final -> allow device to go to power-saving mode */ | ||
1213 | + omap4_sham_write_mask(dd, SHA_REG_CTRL, 0, SHA_REG_CTRL_LENGTH); | ||
1214 | +#endif | ||
1215 | + | ||
1216 | + /* TODO check whether the result needs to be read out here, | ||
1217 | + or if we just disable the interrupt */ | ||
1218 | + omap4_sham_write_mask(dd, SHA_REG_SYSCFG, 0, SHA_REG_SYSCFG_SIT_EN); | ||
1219 | + | ||
1220 | + if (!test_bit(FLAGS_BUSY, &dd->dflags)) { | ||
1221 | + dev_warn(dd->dev, "Interrupt when no active requests.\n"); | ||
1222 | + } else { | ||
1223 | + set_bit(FLAGS_OUTPUT_READY, &dd->dflags); | ||
1224 | + tasklet_schedule(&dd->done_task); | ||
1225 | + } | ||
1226 | + | ||
1227 | + return IRQ_HANDLED; | ||
1228 | +} | ||
1229 | + | ||
1230 | +static void omap4_sham_dma_callback(unsigned int lch, u16 ch_status, void *data) | ||
1231 | +{ | ||
1232 | + struct omap4_sham_dev *dd = data; | ||
1233 | + | ||
1234 | + edma_stop(lch); | ||
1235 | + | ||
1236 | + if (ch_status != DMA_COMPLETE) { | ||
1237 | + pr_err("omap4-sham DMA error status: 0x%hx\n", ch_status); | ||
1238 | + dd->err = -EIO; | ||
1239 | + clear_bit(FLAGS_INIT, &dd->dflags); /* request to re-initialize */ | ||
1240 | + } | ||
1241 | + | ||
1242 | + set_bit(FLAGS_DMA_READY, &dd->dflags); | ||
1243 | + tasklet_schedule(&dd->done_task); | ||
1244 | +} | ||
1245 | + | ||
1246 | +static int omap4_sham_dma_init(struct omap4_sham_dev *dd) | ||
1247 | +{ | ||
1248 | + int err; | ||
1249 | + | ||
1250 | + dd->dma_lch = -1; | ||
1251 | + | ||
1252 | + dd->dma_lch = edma_alloc_channel(dd->dma, omap4_sham_dma_callback, dd, EVENTQ_2); | ||
1253 | + if (dd->dma_lch < 0) { | ||
1254 | + dev_err(dd->dev, "Unable to request EDMA channel\n"); | ||
1255 | + return -1; | ||
1256 | + } | ||
1257 | + | ||
1258 | + return 0; | ||
1259 | +} | ||
1260 | + | ||
1261 | +static void omap4_sham_dma_cleanup(struct omap4_sham_dev *dd) | ||
1262 | +{ | ||
1263 | + if (dd->dma_lch >= 0) { | ||
1264 | + edma_free_channel(dd->dma_lch); | ||
1265 | + dd->dma_lch = -1; | ||
1266 | + } | ||
1267 | +} | ||
1268 | + | ||
1269 | +static int __devinit omap4_sham_probe(struct platform_device *pdev) | ||
1270 | +{ | ||
1271 | + struct omap4_sham_dev *dd; | ||
1272 | + struct device *dev = &pdev->dev; | ||
1273 | + struct resource *res; | ||
1274 | + int err, i, j; | ||
1275 | + u32 reg; | ||
1276 | + | ||
1277 | + dd = kzalloc(sizeof(struct omap4_sham_dev), GFP_KERNEL); | ||
1278 | + if (dd == NULL) { | ||
1279 | + dev_err(dev, "unable to alloc data struct.\n"); | ||
1280 | + err = -ENOMEM; | ||
1281 | + goto data_err; | ||
1282 | + } | ||
1283 | + dd->dev = dev; | ||
1284 | + platform_set_drvdata(pdev, dd); | ||
1285 | + | ||
1286 | + INIT_LIST_HEAD(&dd->list); | ||
1287 | + spin_lock_init(&dd->lock); | ||
1288 | + tasklet_init(&dd->done_task, omap4_sham_done_task, (unsigned long)dd); | ||
1289 | + crypto_init_queue(&dd->queue, AM33X_SHAM_QUEUE_LENGTH); | ||
1290 | + | ||
1291 | + dd->irq = -1; | ||
1292 | + | ||
1293 | + /* Get the base address */ | ||
1294 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1295 | + if (!res) { | ||
1296 | + dev_err(dev, "no MEM resource info\n"); | ||
1297 | + err = -ENODEV; | ||
1298 | + goto res_err; | ||
1299 | + } | ||
1300 | + dd->phys_base = res->start; | ||
1301 | + | ||
1302 | + /* Get the DMA */ | ||
1303 | + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
1304 | + if (!res) { | ||
1305 | + dev_err(dev, "no DMA resource info\n"); | ||
1306 | + err = -ENODEV; | ||
1307 | + goto res_err; | ||
1308 | + } | ||
1309 | + dd->dma = res->start; | ||
1310 | + | ||
1311 | + /* Get the IRQ */ | ||
1312 | + dd->irq = platform_get_irq(pdev, 0); | ||
1313 | + if (dd->irq < 0) { | ||
1314 | + dev_err(dev, "no IRQ resource info\n"); | ||
1315 | + err = dd->irq; | ||
1316 | + goto res_err; | ||
1317 | + } | ||
1318 | + | ||
1319 | + err = request_irq(dd->irq, omap4_sham_irq, | ||
1320 | + IRQF_TRIGGER_LOW, dev_name(dev), dd); | ||
1321 | + if (err) { | ||
1322 | + dev_err(dev, "unable to request irq.\n"); | ||
1323 | + goto res_err; | ||
1324 | + } | ||
1325 | + | ||
1326 | + err = omap4_sham_dma_init(dd); | ||
1327 | + if (err) | ||
1328 | + goto dma_err; | ||
1329 | + | ||
1330 | + /* Initializing the clock */ | ||
1331 | + dd->iclk = clk_get(dev, "sha0_fck"); | ||
1332 | + if (IS_ERR(dd->iclk)) { | ||
1333 | + dev_err(dev, "clock initialization failed.\n"); | ||
1334 | + err = PTR_ERR(dd->iclk); | ||
1335 | + goto clk_err; | ||
1336 | + } | ||
1337 | + | ||
1338 | + dd->io_base = ioremap(dd->phys_base, SZ_4K); | ||
1339 | + if (!dd->io_base) { | ||
1340 | + dev_err(dev, "can't ioremap\n"); | ||
1341 | + err = -ENOMEM; | ||
1342 | + goto io_err; | ||
1343 | + } | ||
1344 | + | ||
1345 | + clk_enable(dd->iclk); | ||
1346 | + reg = omap4_sham_read(dd, SHA_REG_REV); | ||
1347 | + clk_disable(dd->iclk); | ||
1348 | + | ||
1349 | + dev_info(dev, "AM33X SHA/MD5 hw accel rev: %u.%02u\n", | ||
1350 | + (reg & SHA_REG_REV_X_MAJOR_MASK) >> 8, reg & SHA_REG_REV_Y_MINOR_MASK); | ||
1351 | + | ||
1352 | + spin_lock(&sham.lock); | ||
1353 | + list_add_tail(&dd->list, &sham.dev_list); | ||
1354 | + spin_unlock(&sham.lock); | ||
1355 | + | ||
1356 | + for (i = 0; i < ARRAY_SIZE(algs); i++) { | ||
1357 | + err = crypto_register_ahash(&algs[i]); | ||
1358 | + if (err) | ||
1359 | + goto err_algs; | ||
1360 | + } | ||
1361 | + | ||
1362 | + pr_info("probe() done\n"); | ||
1363 | + | ||
1364 | + return 0; | ||
1365 | + | ||
1366 | +err_algs: | ||
1367 | + for (j = 0; j < i; j++) | ||
1368 | + crypto_unregister_ahash(&algs[j]); | ||
1369 | + iounmap(dd->io_base); | ||
1370 | +io_err: | ||
1371 | + clk_put(dd->iclk); | ||
1372 | +clk_err: | ||
1373 | + omap4_sham_dma_cleanup(dd); | ||
1374 | +dma_err: | ||
1375 | + if (dd->irq >= 0) | ||
1376 | + free_irq(dd->irq, dd); | ||
1377 | +res_err: | ||
1378 | + kfree(dd); | ||
1379 | + dd = NULL; | ||
1380 | +data_err: | ||
1381 | + dev_err(dev, "initialization failed.\n"); | ||
1382 | + | ||
1383 | + return err; | ||
1384 | +} | ||
1385 | + | ||
1386 | +static int __devexit omap4_sham_remove(struct platform_device *pdev) | ||
1387 | +{ | ||
1388 | + static struct omap4_sham_dev *dd; | ||
1389 | + int i; | ||
1390 | + | ||
1391 | + dd = platform_get_drvdata(pdev); | ||
1392 | + if (!dd) | ||
1393 | + return -ENODEV; | ||
1394 | + spin_lock(&sham.lock); | ||
1395 | + list_del(&dd->list); | ||
1396 | + spin_unlock(&sham.lock); | ||
1397 | + for (i = 0; i < ARRAY_SIZE(algs); i++) | ||
1398 | + crypto_unregister_ahash(&algs[i]); | ||
1399 | + tasklet_kill(&dd->done_task); | ||
1400 | + iounmap(dd->io_base); | ||
1401 | + clk_put(dd->iclk); | ||
1402 | + omap4_sham_dma_cleanup(dd); | ||
1403 | + if (dd->irq >= 0) | ||
1404 | + free_irq(dd->irq, dd); | ||
1405 | + kfree(dd); | ||
1406 | + dd = NULL; | ||
1407 | + | ||
1408 | + return 0; | ||
1409 | +} | ||
1410 | + | ||
1411 | +static struct platform_driver omap4_sham_driver = { | ||
1412 | + .probe = omap4_sham_probe, | ||
1413 | + .remove = omap4_sham_remove, | ||
1414 | + .driver = { | ||
1415 | + .name = "omap4-sham", | ||
1416 | + .owner = THIS_MODULE, | ||
1417 | + }, | ||
1418 | +}; | ||
1419 | + | ||
1420 | +static int __init omap4_sham_mod_init(void) | ||
1421 | +{ | ||
1422 | + pr_info("loading AM33X SHA/MD5 driver\n"); | ||
1423 | + | ||
1424 | + if (!cpu_is_am33xx() || omap_type() != OMAP2_DEVICE_TYPE_GP) { | ||
1425 | + pr_err("Unsupported cpu\n"); | ||
1426 | + return -ENODEV; | ||
1427 | + } | ||
1428 | + | ||
1429 | + return platform_driver_register(&omap4_sham_driver); | ||
1430 | +} | ||
1431 | + | ||
1432 | +static void __exit omap4_sham_mod_exit(void) | ||
1433 | +{ | ||
1434 | + platform_driver_unregister(&omap4_sham_driver); | ||
1435 | +} | ||
1436 | + | ||
1437 | +module_init(omap4_sham_mod_init); | ||
1438 | +module_exit(omap4_sham_mod_exit); | ||
1439 | + | ||
1440 | +MODULE_DESCRIPTION("AM33x SHA/MD5 hw acceleration support."); | ||
1441 | +MODULE_LICENSE("GPL v2"); | ||
1442 | +MODULE_AUTHOR("Herman Schuurman"); | ||
1443 | -- | ||
1444 | 1.7.0.4 | ||