aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto
diff options
context:
space:
mode:
authorDmitry Kasatkin <dmitry.kasatkin@nokia.com>2010-11-19 09:04:24 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2010-11-27 03:37:17 -0500
commit3e133c8bf6a6723377d94bc97aa52596e49a4090 (patch)
treee04e9dfcfbfc95ad5a529dd10b504c1dce22ae66 /drivers/crypto
parentc8eb54041acc4dedeaf0d9da34b91b8658386751 (diff)
crypto: omap-sham - error handling improved
Introduces DMA error handling. DMA error is returned as a result code of the hash request. Clients needs to handle error codes and may repeat hash calculation attempt. Also in the case of DMA error, SHAM module is set to be re-initialized again. It significantly improves stability against possible HW failures. Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/omap-sham.c67
1 files changed, 44 insertions, 23 deletions
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 9dfbc4ab7711..db206284835a 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -83,6 +83,7 @@
83#define FLAGS_INIT 0x0100 83#define FLAGS_INIT 0x0100
84#define FLAGS_CPU 0x0200 84#define FLAGS_CPU 0x0200
85#define FLAGS_HMAC 0x0400 85#define FLAGS_HMAC 0x0400
86#define FLAGS_ERROR 0x0800
86 87
87/* 3rd byte */ 88/* 3rd byte */
88#define FLAGS_BUSY 16 89#define FLAGS_BUSY 16
@@ -137,6 +138,7 @@ struct omap_sham_dev {
137 int irq; 138 int irq;
138 struct clk *iclk; 139 struct clk *iclk;
139 spinlock_t lock; 140 spinlock_t lock;
141 int err;
140 int dma; 142 int dma;
141 int dma_lch; 143 int dma_lch;
142 struct tasklet_struct done_task; 144 struct tasklet_struct done_task;
@@ -234,10 +236,12 @@ static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
234 SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); 236 SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);
235 237
236 if (omap_sham_wait(dd, SHA_REG_SYSSTATUS, 238 if (omap_sham_wait(dd, SHA_REG_SYSSTATUS,
237 SHA_REG_SYSSTATUS_RESETDONE)) 239 SHA_REG_SYSSTATUS_RESETDONE)) {
240 clk_disable(dd->iclk);
238 return -ETIMEDOUT; 241 return -ETIMEDOUT;
239 242 }
240 dd->flags |= FLAGS_INIT; 243 dd->flags |= FLAGS_INIT;
244 dd->err = 0;
241 } 245 }
242 } else { 246 } else {
243 omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt); 247 omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt);
@@ -279,11 +283,12 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
279 if (err) 283 if (err)
280 return err; 284 return err;
281 285
286 /* should be non-zero before next lines to disable clocks later */
287 ctx->digcnt += length;
288
282 if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY)) 289 if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY))
283 return -ETIMEDOUT; 290 return -ETIMEDOUT;
284 291
285 ctx->digcnt += length;
286
287 if (final) 292 if (final)
288 ctx->flags |= FLAGS_FINAL; /* catch last interrupt */ 293 ctx->flags |= FLAGS_FINAL; /* catch last interrupt */
289 294
@@ -303,7 +308,6 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
303 308
304 dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n", 309 dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
305 ctx->digcnt, length, final); 310 ctx->digcnt, length, final);
306
307 /* flush cache entries related to our page */ 311 /* flush cache entries related to our page */
308 if (dma_addr == ctx->dma_addr) 312 if (dma_addr == ctx->dma_addr)
309 dma_sync_single_for_device(dd->dev, dma_addr, length, 313 dma_sync_single_for_device(dd->dev, dma_addr, length,
@@ -411,6 +415,7 @@ static int omap_sham_update_dma_fast(struct omap_sham_dev *dd)
411{ 415{
412 struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); 416 struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
413 unsigned int length; 417 unsigned int length;
418 int err;
414 419
415 ctx->flags |= FLAGS_FAST; 420 ctx->flags |= FLAGS_FAST;
416 421
@@ -424,7 +429,11 @@ static int omap_sham_update_dma_fast(struct omap_sham_dev *dd)
424 429
425 ctx->total -= length; 430 ctx->total -= length;
426 431
427 return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); 432 err = omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1);
433 if (err != -EINPROGRESS)
434 dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
435
436 return err;
428} 437}
429 438
430static int omap_sham_update_cpu(struct omap_sham_dev *dd) 439static int omap_sham_update_cpu(struct omap_sham_dev *dd)
@@ -580,9 +589,6 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
580 589
581 ctx->bufcnt = 0; 590 ctx->bufcnt = 0;
582 591
583 if (err != -EINPROGRESS)
584 omap_sham_cleanup(req);
585
586 dev_dbg(dd->dev, "final_req: err: %d\n", err); 592 dev_dbg(dd->dev, "final_req: err: %d\n", err);
587 593
588 return err; 594 return err;
@@ -616,9 +622,11 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
616 omap_sham_copy_hash(ctx->dd->req, 1); 622 omap_sham_copy_hash(ctx->dd->req, 1);
617 if (ctx->flags & FLAGS_HMAC) 623 if (ctx->flags & FLAGS_HMAC)
618 err = omap_sham_finish_req_hmac(req); 624 err = omap_sham_finish_req_hmac(req);
625 } else {
626 ctx->flags |= FLAGS_ERROR;
619 } 627 }
620 628
621 if (ctx->flags & FLAGS_FINAL) 629 if ((ctx->flags & FLAGS_FINAL) || err)
622 omap_sham_cleanup(req); 630 omap_sham_cleanup(req);
623 631
624 clear_bit(FLAGS_BUSY, &ctx->dd->flags); 632 clear_bit(FLAGS_BUSY, &ctx->dd->flags);
@@ -776,12 +784,14 @@ static int omap_sham_final(struct ahash_request *req)
776 784
777 ctx->flags |= FLAGS_FINUP; 785 ctx->flags |= FLAGS_FINUP;
778 786
779 /* OMAP HW accel works only with buffers >= 9 */ 787 if (!(ctx->flags & FLAGS_ERROR)) {
780 /* HMAC is always >= 9 because of ipad */ 788 /* OMAP HW accel works only with buffers >= 9 */
781 if ((ctx->digcnt + ctx->bufcnt) < 9) 789 /* HMAC is always >= 9 because of ipad */
782 err = omap_sham_final_shash(req); 790 if ((ctx->digcnt + ctx->bufcnt) < 9)
783 else if (ctx->bufcnt) 791 err = omap_sham_final_shash(req);
784 return omap_sham_enqueue(req, OP_FINAL); 792 else if (ctx->bufcnt)
793 return omap_sham_enqueue(req, OP_FINAL);
794 }
785 795
786 omap_sham_cleanup(req); 796 omap_sham_cleanup(req);
787 797
@@ -851,6 +861,8 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
851 struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm); 861 struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
852 const char *alg_name = crypto_tfm_alg_name(tfm); 862 const char *alg_name = crypto_tfm_alg_name(tfm);
853 863
864 pr_info("enter\n");
865
854 /* Allocate a fallback and abort if it failed. */ 866 /* Allocate a fallback and abort if it failed. */
855 tctx->fallback = crypto_alloc_shash(alg_name, 0, 867 tctx->fallback = crypto_alloc_shash(alg_name, 0,
856 CRYPTO_ALG_NEED_FALLBACK); 868 CRYPTO_ALG_NEED_FALLBACK);
@@ -1008,7 +1020,7 @@ static void omap_sham_done_task(unsigned long data)
1008 struct omap_sham_dev *dd = (struct omap_sham_dev *)data; 1020 struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
1009 struct ahash_request *req = dd->req; 1021 struct ahash_request *req = dd->req;
1010 struct omap_sham_reqctx *ctx = ahash_request_ctx(req); 1022 struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
1011 int ready = 1; 1023 int ready = 0, err = 0;
1012 1024
1013 if (ctx->flags & FLAGS_OUTPUT_READY) { 1025 if (ctx->flags & FLAGS_OUTPUT_READY) {
1014 ctx->flags &= ~FLAGS_OUTPUT_READY; 1026 ctx->flags &= ~FLAGS_OUTPUT_READY;
@@ -1018,13 +1030,16 @@ static void omap_sham_done_task(unsigned long data)
1018 if (dd->flags & FLAGS_DMA_ACTIVE) { 1030 if (dd->flags & FLAGS_DMA_ACTIVE) {
1019 dd->flags &= ~FLAGS_DMA_ACTIVE; 1031 dd->flags &= ~FLAGS_DMA_ACTIVE;
1020 omap_sham_update_dma_stop(dd); 1032 omap_sham_update_dma_stop(dd);
1021 omap_sham_update_dma_slow(dd); 1033 if (!dd->err)
1034 err = omap_sham_update_dma_slow(dd);
1022 } 1035 }
1023 1036
1024 if (ready && !(dd->flags & FLAGS_DMA_ACTIVE)) { 1037 err = dd->err ? : err;
1025 dev_dbg(dd->dev, "update done\n"); 1038
1039 if (err != -EINPROGRESS && (ready || err)) {
1040 dev_dbg(dd->dev, "update done: err: %d\n", err);
1026 /* finish curent request */ 1041 /* finish curent request */
1027 omap_sham_finish_req(req, 0); 1042 omap_sham_finish_req(req, err);
1028 /* start new request */ 1043 /* start new request */
1029 omap_sham_handle_queue(dd); 1044 omap_sham_handle_queue(dd);
1030 } 1045 }
@@ -1056,6 +1071,7 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id)
1056 omap_sham_read(dd, SHA_REG_CTRL); 1071 omap_sham_read(dd, SHA_REG_CTRL);
1057 1072
1058 ctx->flags |= FLAGS_OUTPUT_READY; 1073 ctx->flags |= FLAGS_OUTPUT_READY;
1074 dd->err = 0;
1059 tasklet_schedule(&dd->done_task); 1075 tasklet_schedule(&dd->done_task);
1060 1076
1061 return IRQ_HANDLED; 1077 return IRQ_HANDLED;
@@ -1065,8 +1081,13 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
1065{ 1081{
1066 struct omap_sham_dev *dd = data; 1082 struct omap_sham_dev *dd = data;
1067 1083
1068 if (likely(lch == dd->dma_lch)) 1084 if (ch_status != OMAP_DMA_BLOCK_IRQ) {
1069 tasklet_schedule(&dd->done_task); 1085 pr_err("omap-sham DMA error status: 0x%hx\n", ch_status);
1086 dd->err = -EIO;
1087 dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
1088 }
1089
1090 tasklet_schedule(&dd->done_task);
1070} 1091}
1071 1092
1072static int omap_sham_dma_init(struct omap_sham_dev *dd) 1093static int omap_sham_dma_init(struct omap_sham_dev *dd)