Skip to content

Commit

Permalink
crypto: omap-sham - irq and dma handling changes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dmitry Kasatkin authored and Herbert Xu committed Jun 29, 2011
1 parent 6cb3ffe commit 6c63db8
Showing 1 changed file with 27 additions and 13 deletions.
40 changes: 27 additions & 13 deletions drivers/crypto/omap-sham.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#define FLAGS_OUTPUT_READY 3
#define FLAGS_INIT 4
#define FLAGS_CPU 5
#define FLAGS_DMA_READY 6
/* context flags */
#define FLAGS_FINUP 16
#define FLAGS_SG 17
Expand Down Expand Up @@ -304,6 +305,8 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
if (final)
set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */

set_bit(FLAGS_CPU, &dd->flags);

len32 = DIV_ROUND_UP(length, sizeof(u32));

for (count = 0; count < len32; count++)
Expand Down Expand Up @@ -1033,29 +1036,39 @@ static struct ahash_alg algs[] = {
static void omap_sham_done_task(unsigned long data)
{
struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
int ready = 0, err = 0;
int err = 0;

if (!test_bit(FLAGS_BUSY, &dd->flags)) {
omap_sham_handle_queue(dd, NULL);
return;
}

if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
ready = 1;

if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
omap_sham_update_dma_stop(dd);
if (!dd->err)
if (test_bit(FLAGS_CPU, &dd->flags)) {
if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
goto finish;
} else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
omap_sham_update_dma_stop(dd);
if (dd->err) {
err = dd->err;
goto finish;
}
}
if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
/* hash or semi-hash ready */
clear_bit(FLAGS_DMA_READY, &dd->flags);
err = omap_sham_update_dma_start(dd);
if (err != -EINPROGRESS)
goto finish;
}
}

err = dd->err ? : err;
return;

if (err != -EINPROGRESS && (ready || err)) {
dev_dbg(dd->dev, "update done: err: %d\n", err);
/* finish curent request */
omap_sham_finish_req(dd->req, err);
}
finish:
dev_dbg(dd->dev, "update done: err: %d\n", err);
/* finish curent request */
omap_sham_finish_req(dd->req, err);
}

static irqreturn_t omap_sham_irq(int irq, void *dev_id)
Expand Down Expand Up @@ -1087,6 +1100,7 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */
}

set_bit(FLAGS_DMA_READY, &dd->flags);
tasklet_schedule(&dd->done_task);
}

Expand Down

0 comments on commit 6c63db8

Please sign in to comment.