aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2012-06-04 00:24:47 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2012-06-12 04:37:19 -0400
commitb8840098b70c11d70c29263e0765f103e6cbe55e (patch)
tree4d9c7f993f7afd5ac365741976186496a169c74a
parenta482b081a2d4d74d16bc9ea8779f9f6055f95852 (diff)
crypto: bfin_crc - CRC hardware driver for BF60x family processors.
The CRC peripheral is a hardware block used to compute the CRC of the block of data. This is based on a CRC32 engine which computes the CRC value of 32b data words presented to it. For data words of < 32b in size, this driver pack 0 automatically into 32b data units. This driver implements the async hash crypto framework API. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/crypto/Kconfig7
-rw-r--r--drivers/crypto/Makefile3
-rw-r--r--drivers/crypto/bfin_crc.c780
3 files changed, 789 insertions, 1 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 1092a770482..dd4d5af6c31 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -325,4 +325,11 @@ if CRYPTO_DEV_UX500
325 source "drivers/crypto/ux500/Kconfig" 325 source "drivers/crypto/ux500/Kconfig"
326endif # if CRYPTO_DEV_UX500 326endif # if CRYPTO_DEV_UX500
327 327
328config CRYPTO_DEV_BFIN_CRC
329 tristate "Support for Blackfin CRC hardware"
330 depends on BF60x
331 help
332 Newer Blackfin processors have CRC hardware. Select this if you
333 want to use the Blackfin CRC module.
334
328endif # CRYPTO_HW 335endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 01390325d72..d5062bb7a1f 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -14,4 +14,5 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
14obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o 14obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
15obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o 15obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
16obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o 16obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
17obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ \ No newline at end of file 17obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
18obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
new file mode 100644
index 00000000000..5398580b431
--- /dev/null
+++ b/drivers/crypto/bfin_crc.c
@@ -0,0 +1,780 @@
1/*
2 * Cryptographic API.
3 *
4 * Support Blackfin CRC HW acceleration.
5 *
6 * Copyright 2012 Analog Devices Inc.
7 *
8 * Licensed under the GPL-2.
9 */
10
11#include <linux/err.h>
12#include <linux/device.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/errno.h>
16#include <linux/interrupt.h>
17#include <linux/kernel.h>
18#include <linux/irq.h>
19#include <linux/io.h>
20#include <linux/platform_device.h>
21#include <linux/scatterlist.h>
22#include <linux/dma-mapping.h>
23#include <linux/delay.h>
24#include <linux/unaligned/access_ok.h>
25#include <linux/crypto.h>
26#include <linux/cryptohash.h>
27#include <crypto/scatterwalk.h>
28#include <crypto/algapi.h>
29#include <crypto/hash.h>
30#include <crypto/internal/hash.h>
31
32#include <asm/blackfin.h>
33#include <asm/bfin_crc.h>
34#include <asm/dma.h>
35#include <asm/portmux.h>
36
37#define CRC_CCRYPTO_QUEUE_LENGTH 5
38
39#define DRIVER_NAME "bfin-hmac-crc"
40#define CHKSUM_DIGEST_SIZE 4
41#define CHKSUM_BLOCK_SIZE 1
42
43#define CRC_MAX_DMA_DESC 100
44
45#define CRC_CRYPTO_STATE_UPDATE 1
46#define CRC_CRYPTO_STATE_FINALUPDATE 2
47#define CRC_CRYPTO_STATE_FINISH 3
48
49struct bfin_crypto_crc {
50 struct list_head list;
51 struct device *dev;
52 spinlock_t lock;
53
54 int irq;
55 int dma_ch;
56 u32 poly;
57 volatile struct crc_register *regs;
58
59 struct ahash_request *req; /* current request in operation */
60 struct dma_desc_array *sg_cpu; /* virt addr of sg dma descriptors */
61 dma_addr_t sg_dma; /* phy addr of sg dma descriptors */
62 u8 *sg_mid_buf;
63
64 struct tasklet_struct done_task;
65 struct crypto_queue queue; /* waiting requests */
66
67 u8 busy:1; /* crc device in operation flag */
68};
69
70static struct bfin_crypto_crc_list {
71 struct list_head dev_list;
72 spinlock_t lock;
73} crc_list;
74
75struct bfin_crypto_crc_reqctx {
76 struct bfin_crypto_crc *crc;
77
78 unsigned int total; /* total request bytes */
79 size_t sg_buflen; /* bytes for this update */
80 unsigned int sg_nents;
81 struct scatterlist *sg; /* sg list head for this update*/
82 struct scatterlist bufsl[2]; /* chained sg list */
83
84 size_t bufnext_len;
85 size_t buflast_len;
86 u8 bufnext[CHKSUM_DIGEST_SIZE]; /* extra bytes for next udpate */
87 u8 buflast[CHKSUM_DIGEST_SIZE]; /* extra bytes from last udpate */
88
89 u8 flag;
90};
91
92struct bfin_crypto_crc_ctx {
93 struct bfin_crypto_crc *crc;
94 u32 key;
95};
96
97
98/*
99 * derive number of elements in scatterlist
100 */
101static int sg_count(struct scatterlist *sg_list)
102{
103 struct scatterlist *sg = sg_list;
104 int sg_nents = 1;
105
106 if (sg_list == NULL)
107 return 0;
108
109 while (!sg_is_last(sg)) {
110 sg_nents++;
111 sg = scatterwalk_sg_next(sg);
112 }
113
114 return sg_nents;
115}
116
117/*
118 * get element in scatter list by given index
119 */
120static struct scatterlist *sg_get(struct scatterlist *sg_list, unsigned int nents,
121 unsigned int index)
122{
123 struct scatterlist *sg = NULL;
124 int i;
125
126 for_each_sg(sg_list, sg, nents, i)
127 if (i == index)
128 break;
129
130 return sg;
131}
132
133static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key)
134{
135 crc->regs->datacntrld = 0;
136 crc->regs->control = MODE_CALC_CRC << OPMODE_OFFSET;
137 crc->regs->curresult = key;
138
139 /* setup CRC interrupts */
140 crc->regs->status = CMPERRI | DCNTEXPI;
141 crc->regs->intrenset = CMPERRI | DCNTEXPI;
142 SSYNC();
143
144 return 0;
145}
146
147static int bfin_crypto_crc_init(struct ahash_request *req)
148{
149 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
150 struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
151 struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
152 struct bfin_crypto_crc *crc;
153
154 dev_dbg(crc->dev, "crc_init\n");
155 spin_lock_bh(&crc_list.lock);
156 list_for_each_entry(crc, &crc_list.dev_list, list) {
157 crc_ctx->crc = crc;
158 break;
159 }
160 spin_unlock_bh(&crc_list.lock);
161
162 if (sg_count(req->src) > CRC_MAX_DMA_DESC) {
163 dev_dbg(crc->dev, "init: requested sg list is too big > %d\n",
164 CRC_MAX_DMA_DESC);
165 return -EINVAL;
166 }
167
168 ctx->crc = crc;
169 ctx->bufnext_len = 0;
170 ctx->buflast_len = 0;
171 ctx->sg_buflen = 0;
172 ctx->total = 0;
173 ctx->flag = 0;
174
175 /* init crc results */
176 put_unaligned_le32(crc_ctx->key, req->result);
177
178 dev_dbg(crc->dev, "init: digest size: %d\n",
179 crypto_ahash_digestsize(tfm));
180
181 return bfin_crypto_crc_init_hw(crc, crc_ctx->key);
182}
183
184static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
185{
186 struct scatterlist *sg;
187 struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(crc->req);
188 int i = 0, j = 0;
189 unsigned long dma_config;
190 unsigned int dma_count;
191 unsigned int dma_addr;
192 unsigned int mid_dma_count = 0;
193 int dma_mod;
194
195 dma_map_sg(crc->dev, ctx->sg, ctx->sg_nents, DMA_TO_DEVICE);
196
197 for_each_sg(ctx->sg, sg, ctx->sg_nents, j) {
198 dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32;
199 dma_addr = sg_dma_address(sg);
200 /* deduce extra bytes in last sg */
201 if (sg_is_last(sg))
202 dma_count = sg_dma_len(sg) - ctx->bufnext_len;
203 else
204 dma_count = sg_dma_len(sg);
205
206 if (mid_dma_count) {
207 /* Append last middle dma buffer to 4 bytes with first
208 bytes in current sg buffer. Move addr of current
209 sg and deduce the length of current sg.
210 */
211 memcpy(crc->sg_mid_buf +((i-1) << 2) + mid_dma_count,
212 (void *)dma_addr,
213 CHKSUM_DIGEST_SIZE - mid_dma_count);
214 dma_addr += CHKSUM_DIGEST_SIZE - mid_dma_count;
215 dma_count -= CHKSUM_DIGEST_SIZE - mid_dma_count;
216 }
217 /* chop current sg dma len to multiple of 32 bits */
218 mid_dma_count = dma_count % 4;
219 dma_count &= ~0x3;
220
221 if (dma_addr % 4 == 0) {
222 dma_config |= WDSIZE_32;
223 dma_count >>= 2;
224 dma_mod = 4;
225 } else if (dma_addr % 2 == 0) {
226 dma_config |= WDSIZE_16;
227 dma_count >>= 1;
228 dma_mod = 2;
229 } else {
230 dma_config |= WDSIZE_8;
231 dma_mod = 1;
232 }
233
234 crc->sg_cpu[i].start_addr = dma_addr;
235 crc->sg_cpu[i].cfg = dma_config;
236 crc->sg_cpu[i].x_count = dma_count;
237 crc->sg_cpu[i].x_modify = dma_mod;
238 dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
239 "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
240 i, crc->sg_cpu[i].start_addr,
241 crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
242 crc->sg_cpu[i].x_modify);
243 i++;
244
245 if (mid_dma_count) {
246 /* copy extra bytes to next middle dma buffer */
247 dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 |
248 DMAEN | PSIZE_32 | WDSIZE_32;
249 memcpy(crc->sg_mid_buf + (i << 2),
250 (void *)(dma_addr + (dma_count << 2)),
251 mid_dma_count);
252 /* setup new dma descriptor for next middle dma */
253 crc->sg_cpu[i].start_addr = dma_map_single(crc->dev,
254 crc->sg_mid_buf + (i << 2),
255 CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
256 crc->sg_cpu[i].cfg = dma_config;
257 crc->sg_cpu[i].x_count = 1;
258 crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
259 dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
260 "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
261 i, crc->sg_cpu[i].start_addr,
262 crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
263 crc->sg_cpu[i].x_modify);
264 i++;
265 }
266 }
267
268 dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32 | WDSIZE_32;
269 /* For final update req, append the buffer for next update as well*/
270 if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
271 ctx->flag == CRC_CRYPTO_STATE_FINISH)) {
272 crc->sg_cpu[i].start_addr = dma_map_single(crc->dev, ctx->bufnext,
273 CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
274 crc->sg_cpu[i].cfg = dma_config;
275 crc->sg_cpu[i].x_count = 1;
276 crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
277 dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
278 "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
279 i, crc->sg_cpu[i].start_addr,
280 crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
281 crc->sg_cpu[i].x_modify);
282 i++;
283 }
284
285 if (i == 0)
286 return;
287
288 flush_dcache_range((unsigned int)crc->sg_cpu,
289 (unsigned int)crc->sg_cpu +
290 i * sizeof(struct dma_desc_array));
291
292 /* Set the last descriptor to stop mode */
293 crc->sg_cpu[i - 1].cfg &= ~(DMAFLOW | NDSIZE);
294 crc->sg_cpu[i - 1].cfg |= DI_EN;
295 set_dma_curr_desc_addr(crc->dma_ch, (unsigned long *)crc->sg_dma);
296 set_dma_x_count(crc->dma_ch, 0);
297 set_dma_x_modify(crc->dma_ch, 0);
298 SSYNC();
299 set_dma_config(crc->dma_ch, dma_config);
300}
301
302static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc,
303 struct ahash_request *req)
304{
305 struct crypto_async_request *async_req, *backlog;
306 struct bfin_crypto_crc_reqctx *ctx;
307 struct scatterlist *sg;
308 int ret = 0;
309 int nsg, i, j;
310 unsigned int nextlen;
311 unsigned long flags;
312
313 spin_lock_irqsave(&crc->lock, flags);
314 if (req)
315 ret = ahash_enqueue_request(&crc->queue, req);
316 if (crc->busy) {
317 spin_unlock_irqrestore(&crc->lock, flags);
318 return ret;
319 }
320 backlog = crypto_get_backlog(&crc->queue);
321 async_req = crypto_dequeue_request(&crc->queue);
322 if (async_req)
323 crc->busy = 1;
324 spin_unlock_irqrestore(&crc->lock, flags);
325
326 if (!async_req)
327 return ret;
328
329 if (backlog)
330 backlog->complete(backlog, -EINPROGRESS);
331
332 req = ahash_request_cast(async_req);
333 crc->req = req;
334 ctx = ahash_request_ctx(req);
335 ctx->sg = NULL;
336 ctx->sg_buflen = 0;
337 ctx->sg_nents = 0;
338
339 dev_dbg(crc->dev, "handling new req, flag=%u, nbytes: %d\n",
340 ctx->flag, req->nbytes);
341
342 if (ctx->flag == CRC_CRYPTO_STATE_FINISH) {
343 if (ctx->bufnext_len == 0) {
344 crc->busy = 0;
345 return 0;
346 }
347
348 /* Pack last crc update buffer to 32bit */
349 memset(ctx->bufnext + ctx->bufnext_len, 0,
350 CHKSUM_DIGEST_SIZE - ctx->bufnext_len);
351 } else {
352 /* Pack small data which is less than 32bit to buffer for next update. */
353 if (ctx->bufnext_len + req->nbytes < CHKSUM_DIGEST_SIZE) {
354 memcpy(ctx->bufnext + ctx->bufnext_len,
355 sg_virt(req->src), req->nbytes);
356 ctx->bufnext_len += req->nbytes;
357 if (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE &&
358 ctx->bufnext_len) {
359 goto finish_update;
360 } else {
361 crc->busy = 0;
362 return 0;
363 }
364 }
365
366 if (ctx->bufnext_len) {
367 /* Chain in extra bytes of last update */
368 ctx->buflast_len = ctx->bufnext_len;
369 memcpy(ctx->buflast, ctx->bufnext, ctx->buflast_len);
370
371 nsg = ctx->sg_buflen ? 2 : 1;
372 sg_init_table(ctx->bufsl, nsg);
373 sg_set_buf(ctx->bufsl, ctx->buflast, ctx->buflast_len);
374 if (nsg > 1)
375 scatterwalk_sg_chain(ctx->bufsl, nsg,
376 req->src);
377 ctx->sg = ctx->bufsl;
378 } else
379 ctx->sg = req->src;
380
381 /* Chop crc buffer size to multiple of 32 bit */
382 nsg = ctx->sg_nents = sg_count(ctx->sg);
383 ctx->sg_buflen = ctx->buflast_len + req->nbytes;
384 ctx->bufnext_len = ctx->sg_buflen % 4;
385 ctx->sg_buflen &= ~0x3;
386
387 if (ctx->bufnext_len) {
388 /* copy extra bytes to buffer for next update */
389 memset(ctx->bufnext, 0, CHKSUM_DIGEST_SIZE);
390 nextlen = ctx->bufnext_len;
391 for (i = nsg - 1; i >= 0; i--) {
392 sg = sg_get(ctx->sg, nsg, i);
393 j = min(nextlen, sg_dma_len(sg));
394 memcpy(ctx->bufnext + nextlen - j,
395 sg_virt(sg) + sg_dma_len(sg) - j, j);
396 if (j == sg_dma_len(sg))
397 ctx->sg_nents--;
398 nextlen -= j;
399 if (nextlen == 0)
400 break;
401 }
402 }
403 }
404
405finish_update:
406 if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
407 ctx->flag == CRC_CRYPTO_STATE_FINISH))
408 ctx->sg_buflen += CHKSUM_DIGEST_SIZE;
409
410 /* set CRC data count before start DMA */
411 crc->regs->datacnt = ctx->sg_buflen >> 2;
412
413 /* setup and enable CRC DMA */
414 bfin_crypto_crc_config_dma(crc);
415
416 /* finally kick off CRC operation */
417 crc->regs->control |= BLKEN;
418 SSYNC();
419
420 return -EINPROGRESS;
421}
422
423static int bfin_crypto_crc_update(struct ahash_request *req)
424{
425 struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
426
427 if (!req->nbytes)
428 return 0;
429
430 dev_dbg(ctx->crc->dev, "crc_update\n");
431 ctx->total += req->nbytes;
432 ctx->flag = CRC_CRYPTO_STATE_UPDATE;
433
434 return bfin_crypto_crc_handle_queue(ctx->crc, req);
435}
436
437static int bfin_crypto_crc_final(struct ahash_request *req)
438{
439 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
440 struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
441 struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
442
443 dev_dbg(ctx->crc->dev, "crc_final\n");
444 ctx->flag = CRC_CRYPTO_STATE_FINISH;
445 crc_ctx->key = 0;
446
447 return bfin_crypto_crc_handle_queue(ctx->crc, req);
448}
449
450static int bfin_crypto_crc_finup(struct ahash_request *req)
451{
452 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
453 struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
454 struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
455
456 dev_dbg(ctx->crc->dev, "crc_finishupdate\n");
457 ctx->total += req->nbytes;
458 ctx->flag = CRC_CRYPTO_STATE_FINALUPDATE;
459 crc_ctx->key = 0;
460
461 return bfin_crypto_crc_handle_queue(ctx->crc, req);
462}
463
464static int bfin_crypto_crc_digest(struct ahash_request *req)
465{
466 int ret;
467
468 ret = bfin_crypto_crc_init(req);
469 if (ret)
470 return ret;
471
472 return bfin_crypto_crc_finup(req);
473}
474
475static int bfin_crypto_crc_setkey(struct crypto_ahash *tfm, const u8 *key,
476 unsigned int keylen)
477{
478 struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
479
480 dev_dbg(crc_ctx->crc->dev, "crc_setkey\n");
481 if (keylen != CHKSUM_DIGEST_SIZE) {
482 crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
483 return -EINVAL;
484 }
485
486 crc_ctx->key = get_unaligned_le32(key);
487
488 return 0;
489}
490
491static int bfin_crypto_crc_cra_init(struct crypto_tfm *tfm)
492{
493 struct bfin_crypto_crc_ctx *crc_ctx = crypto_tfm_ctx(tfm);
494
495 crc_ctx->key = 0;
496 crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
497 sizeof(struct bfin_crypto_crc_reqctx));
498
499 return 0;
500}
501
502static void bfin_crypto_crc_cra_exit(struct crypto_tfm *tfm)
503{
504}
505
506static struct ahash_alg algs = {
507 .init = bfin_crypto_crc_init,
508 .update = bfin_crypto_crc_update,
509 .final = bfin_crypto_crc_final,
510 .finup = bfin_crypto_crc_finup,
511 .digest = bfin_crypto_crc_digest,
512 .setkey = bfin_crypto_crc_setkey,
513 .halg.digestsize = CHKSUM_DIGEST_SIZE,
514 .halg.base = {
515 .cra_name = "hmac(crc32)",
516 .cra_driver_name = DRIVER_NAME,
517 .cra_priority = 100,
518 .cra_flags = CRYPTO_ALG_TYPE_AHASH |
519 CRYPTO_ALG_ASYNC,
520 .cra_blocksize = CHKSUM_BLOCK_SIZE,
521 .cra_ctxsize = sizeof(struct bfin_crypto_crc_ctx),
522 .cra_alignmask = 3,
523 .cra_module = THIS_MODULE,
524 .cra_init = bfin_crypto_crc_cra_init,
525 .cra_exit = bfin_crypto_crc_cra_exit,
526 }
527};
528
529static void bfin_crypto_crc_done_task(unsigned long data)
530{
531 struct bfin_crypto_crc *crc = (struct bfin_crypto_crc *)data;
532
533 bfin_crypto_crc_handle_queue(crc, NULL);
534}
535
536static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id)
537{
538 struct bfin_crypto_crc *crc = dev_id;
539
540 if (crc->regs->status & DCNTEXP) {
541 crc->regs->status = DCNTEXP;
542 SSYNC();
543
544 /* prepare results */
545 put_unaligned_le32(crc->regs->result, crc->req->result);
546
547 crc->regs->control &= ~BLKEN;
548 crc->busy = 0;
549
550 if (crc->req->base.complete)
551 crc->req->base.complete(&crc->req->base, 0);
552
553 tasklet_schedule(&crc->done_task);
554
555 return IRQ_HANDLED;
556 } else
557 return IRQ_NONE;
558}
559
560#ifdef CONFIG_PM
561/**
562 * bfin_crypto_crc_suspend - suspend crc device
563 * @pdev: device being suspended
564 * @state: requested suspend state
565 */
566static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t state)
567{
568 struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
569 int i = 100000;
570
571 while ((crc->regs->control & BLKEN) && --i)
572 cpu_relax();
573
574 if (i == 0)
575 return -EBUSY;
576
577 return 0;
578}
579#else
580# define bfin_crypto_crc_suspend NULL
581#endif
582
583#define bfin_crypto_crc_resume NULL
584
585/**
586 * bfin_crypto_crc_probe - Initialize module
587 *
588 */
589static int __devinit bfin_crypto_crc_probe(struct platform_device *pdev)
590{
591 struct device *dev = &pdev->dev;
592 struct resource *res;
593 struct bfin_crypto_crc *crc;
594 unsigned int timeout = 100000;
595 int ret;
596
597 crc = kzalloc(sizeof(*crc), GFP_KERNEL);
598 if (!crc) {
599 dev_err(&pdev->dev, "fail to malloc bfin_crypto_crc\n");
600 return -ENOMEM;
601 }
602
603 crc->dev = dev;
604
605 INIT_LIST_HEAD(&crc->list);
606 spin_lock_init(&crc->lock);
607 tasklet_init(&crc->done_task, bfin_crypto_crc_done_task, (unsigned long)crc);
608 crypto_init_queue(&crc->queue, CRC_CCRYPTO_QUEUE_LENGTH);
609
610 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
611 if (res == NULL) {
612 dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
613 ret = -ENOENT;
614 goto out_error_free_mem;
615 }
616
617 crc->regs = ioremap(res->start, resource_size(res));
618 if (!crc->regs) {
619 dev_err(&pdev->dev, "Cannot map CRC IO\n");
620 ret = -ENXIO;
621 goto out_error_free_mem;
622 }
623
624 crc->irq = platform_get_irq(pdev, 0);
625 if (crc->irq < 0) {
626 dev_err(&pdev->dev, "No CRC DCNTEXP IRQ specified\n");
627 ret = -ENOENT;
628 goto out_error_unmap;
629 }
630
631 ret = request_irq(crc->irq, bfin_crypto_crc_handler, IRQF_SHARED, dev_name(dev), crc);
632 if (ret) {
633 dev_err(&pdev->dev, "Unable to request blackfin crc irq\n");
634 goto out_error_unmap;
635 }
636
637 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
638 if (res == NULL) {
639 dev_err(&pdev->dev, "No CRC DMA channel specified\n");
640 ret = -ENOENT;
641 goto out_error_irq;
642 }
643 crc->dma_ch = res->start;
644
645 ret = request_dma(crc->dma_ch, dev_name(dev));
646 if (ret) {
647 dev_err(&pdev->dev, "Unable to attach Blackfin CRC DMA channel\n");
648 goto out_error_irq;
649 }
650
651 crc->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &crc->sg_dma, GFP_KERNEL);
652 if (crc->sg_cpu == NULL) {
653 ret = -ENOMEM;
654 goto out_error_dma;
655 }
656 /*
657 * need at most CRC_MAX_DMA_DESC sg + CRC_MAX_DMA_DESC middle +
658 * 1 last + 1 next dma descriptors
659 */
660 crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1));
661
662 crc->regs->control = 0;
663 SSYNC();
664 crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data;
665 SSYNC();
666
667 while (!(crc->regs->status & LUTDONE) && (--timeout) > 0)
668 cpu_relax();
669
670 if (timeout == 0)
671 dev_info(&pdev->dev, "init crc poly timeout\n");
672
673 spin_lock(&crc_list.lock);
674 list_add(&crc->list, &crc_list.dev_list);
675 spin_unlock(&crc_list.lock);
676
677 platform_set_drvdata(pdev, crc);
678
679 ret = crypto_register_ahash(&algs);
680 if (ret) {
681 spin_lock(&crc_list.lock);
682 list_del(&crc->list);
683 spin_unlock(&crc_list.lock);
684 dev_err(&pdev->dev, "Cann't register crypto ahash device\n");
685 goto out_error_dma;
686 }
687
688 dev_info(&pdev->dev, "initialized\n");
689
690 return 0;
691
692out_error_dma:
693 if (crc->sg_cpu)
694 dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma);
695 free_dma(crc->dma_ch);
696out_error_irq:
697 free_irq(crc->irq, crc->dev);
698out_error_unmap:
699 iounmap((void *)crc->regs);
700out_error_free_mem:
701 kfree(crc);
702
703 return ret;
704}
705
706/**
707 * bfin_crypto_crc_remove - Initialize module
708 *
709 */
710static int __devexit bfin_crypto_crc_remove(struct platform_device *pdev)
711{
712 struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
713
714 if (!crc)
715 return -ENODEV;
716
717 spin_lock(&crc_list.lock);
718 list_del(&crc->list);
719 spin_unlock(&crc_list.lock);
720
721 crypto_unregister_ahash(&algs);
722 tasklet_kill(&crc->done_task);
723 iounmap((void *)crc->regs);
724 free_dma(crc->dma_ch);
725 if (crc->irq > 0)
726 free_irq(crc->irq, crc->dev);
727 kfree(crc);
728
729 return 0;
730}
731
732static struct platform_driver bfin_crypto_crc_driver = {
733 .probe = bfin_crypto_crc_probe,
734 .remove = __devexit_p(bfin_crypto_crc_remove),
735 .suspend = bfin_crypto_crc_suspend,
736 .resume = bfin_crypto_crc_resume,
737 .driver = {
738 .name = DRIVER_NAME,
739 .owner = THIS_MODULE,
740 },
741};
742
743/**
744 * bfin_crypto_crc_mod_init - Initialize module
745 *
746 * Checks the module params and registers the platform driver.
747 * Real work is in the platform probe function.
748 */
749static int __init bfin_crypto_crc_mod_init(void)
750{
751 int ret;
752
753 pr_info("Blackfin hardware CRC crypto driver\n");
754
755 INIT_LIST_HEAD(&crc_list.dev_list);
756 spin_lock_init(&crc_list.lock);
757
758 ret = platform_driver_register(&bfin_crypto_crc_driver);
759 if (ret) {
760 pr_info(KERN_ERR "unable to register driver\n");
761 return ret;
762 }
763
764 return 0;
765}
766
767/**
768 * bfin_crypto_crc_mod_exit - Deinitialize module
769 */
770static void __exit bfin_crypto_crc_mod_exit(void)
771{
772 platform_driver_unregister(&bfin_crypto_crc_driver);
773}
774
775module_init(bfin_crypto_crc_mod_init);
776module_exit(bfin_crypto_crc_mod_exit);
777
778MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
779MODULE_DESCRIPTION("Blackfin CRC hardware crypto driver");
780MODULE_LICENSE("GPL");