aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto
diff options
context:
space:
mode:
authorDmitry Kasatkin <dmitry.kasatkin@nokia.com>2011-06-02 14:10:10 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2011-06-29 19:44:04 -0400
commit6c63db821d4663c92cd326f6adb8f3d627971a53 (patch)
tree733b36b077b4cca37f2f9d7846745564ed8fc2f2 /drivers/crypto
parent6cb3ffe100ef4c6d5be0bfe4f8ac6d4227bb91bd (diff)
crypto: omap-sham - irq and dma handling changes
It could be a situation, that tasklet is executed twice because of certain delay between dma callback and irq handler execution. In that case, second tasklet execution could actually corrupt the data of the new started dma transactions. This patch improves tasklet logic and prevents above described cases. 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.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 24de4ace9783..a8de7b890d45 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -79,6 +79,7 @@
79#define FLAGS_OUTPUT_READY 3 79#define FLAGS_OUTPUT_READY 3
80#define FLAGS_INIT 4 80#define FLAGS_INIT 4
81#define FLAGS_CPU 5 81#define FLAGS_CPU 5
82#define FLAGS_DMA_READY 6
82/* context flags */ 83/* context flags */
83#define FLAGS_FINUP 16 84#define FLAGS_FINUP 16
84#define FLAGS_SG 17 85#define FLAGS_SG 17
@@ -304,6 +305,8 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
304 if (final) 305 if (final)
305 set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */ 306 set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
306 307
308 set_bit(FLAGS_CPU, &dd->flags);
309
307 len32 = DIV_ROUND_UP(length, sizeof(u32)); 310 len32 = DIV_ROUND_UP(length, sizeof(u32));
308 311
309 for (count = 0; count < len32; count++) 312 for (count = 0; count < len32; count++)
@@ -1033,29 +1036,39 @@ static struct ahash_alg algs[] = {
1033static void omap_sham_done_task(unsigned long data) 1036static void omap_sham_done_task(unsigned long data)
1034{ 1037{
1035 struct omap_sham_dev *dd = (struct omap_sham_dev *)data; 1038 struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
1036 int ready = 0, err = 0; 1039 int err = 0;
1037 1040
1038 if (!test_bit(FLAGS_BUSY, &dd->flags)) { 1041 if (!test_bit(FLAGS_BUSY, &dd->flags)) {
1039 omap_sham_handle_queue(dd, NULL); 1042 omap_sham_handle_queue(dd, NULL);
1040 return; 1043 return;
1041 } 1044 }
1042 1045
1043 if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) 1046 if (test_bit(FLAGS_CPU, &dd->flags)) {
1044 ready = 1; 1047 if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
1045 1048 goto finish;
1046 if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) { 1049 } else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
1047 omap_sham_update_dma_stop(dd); 1050 if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
1048 if (!dd->err) 1051 omap_sham_update_dma_stop(dd);
1052 if (dd->err) {
1053 err = dd->err;
1054 goto finish;
1055 }
1056 }
1057 if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
1058 /* hash or semi-hash ready */
1059 clear_bit(FLAGS_DMA_READY, &dd->flags);
1049 err = omap_sham_update_dma_start(dd); 1060 err = omap_sham_update_dma_start(dd);
1061 if (err != -EINPROGRESS)
1062 goto finish;
1063 }
1050 } 1064 }
1051 1065
1052 err = dd->err ? : err; 1066 return;
1053 1067
1054 if (err != -EINPROGRESS && (ready || err)) { 1068finish:
1055 dev_dbg(dd->dev, "update done: err: %d\n", err); 1069 dev_dbg(dd->dev, "update done: err: %d\n", err);
1056 /* finish curent request */ 1070 /* finish curent request */
1057 omap_sham_finish_req(dd->req, err); 1071 omap_sham_finish_req(dd->req, err);
1058 }
1059} 1072}
1060 1073
1061static irqreturn_t omap_sham_irq(int irq, void *dev_id) 1074static irqreturn_t omap_sham_irq(int irq, void *dev_id)
@@ -1087,6 +1100,7 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
1087 clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */ 1100 clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */
1088 } 1101 }
1089 1102
1103 set_bit(FLAGS_DMA_READY, &dd->flags);
1090 tasklet_schedule(&dd->done_task); 1104 tasklet_schedule(&dd->done_task);
1091} 1105}
1092 1106