Skip to content

Commit

Permalink
crypto: omap-sham - replace flags operation with atomic bit operations
Browse files Browse the repository at this point in the history
Some flags are changed in interrupt handlers and verified in the tasklet.
There might be a race condition when tasklet is interrupted or another
cpu/core will run IRQ handler and tasklet in parallel.
Atomic bitops functions are now used instead of bitmask operations.

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 ea1fd22 commit a929cbe
Showing 1 changed file with 13 additions and 16 deletions.
29 changes: 13 additions & 16 deletions drivers/crypto/omap-sham.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,15 +240,15 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd)
{
clk_enable(dd->iclk);

if (!(dd->flags & BIT(FLAGS_INIT))) {
if (!test_bit(FLAGS_INIT, &dd->flags)) {
omap_sham_write_mask(dd, SHA_REG_MASK,
SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);

if (omap_sham_wait(dd, SHA_REG_SYSSTATUS,
SHA_REG_SYSSTATUS_RESETDONE))
return -ETIMEDOUT;

dd->flags |= BIT(FLAGS_INIT);
set_bit(FLAGS_INIT, &dd->flags);
dd->err = 0;
}

Expand Down Expand Up @@ -303,7 +303,7 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
return -ETIMEDOUT;

if (final)
ctx->flags |= BIT(FLAGS_FINAL); /* catch last interrupt */
set_bit(FLAGS_FINAL, &ctx->flags); /* catch last interrupt */

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

Expand Down Expand Up @@ -336,9 +336,9 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
ctx->digcnt += length;

if (final)
ctx->flags |= BIT(FLAGS_FINAL); /* catch last interrupt */
set_bit(FLAGS_FINAL, &ctx->flags); /* catch last interrupt */

dd->flags |= BIT(FLAGS_DMA_ACTIVE);
set_bit(FLAGS_DMA_ACTIVE, &dd->flags);

omap_start_dma(dd->dma_lch);

Expand Down Expand Up @@ -642,7 +642,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)

if (!err) {
omap_sham_copy_hash(req, 1);
if (ctx->flags & BIT(FLAGS_FINAL))
if (test_bit(FLAGS_FINAL, &ctx->flags))
err = omap_sham_finish(req);
} else {
ctx->flags |= BIT(FLAGS_ERROR);
Expand All @@ -666,14 +666,14 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
spin_lock_irqsave(&dd->lock, flags);
if (req)
ret = ahash_enqueue_request(&dd->queue, req);
if (dd->flags & BIT(FLAGS_BUSY)) {
if (test_bit(FLAGS_BUSY, &dd->flags)) {
spin_unlock_irqrestore(&dd->lock, flags);
return ret;
}
backlog = crypto_get_backlog(&dd->queue);
async_req = crypto_dequeue_request(&dd->queue);
if (async_req)
dd->flags |= BIT(FLAGS_BUSY);
set_bit(FLAGS_BUSY, &dd->flags);
spin_unlock_irqrestore(&dd->lock, flags);

if (!async_req)
Expand Down Expand Up @@ -1037,13 +1037,10 @@ static void omap_sham_done_task(unsigned long data)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int ready = 0, err = 0;

if (ctx->flags & BIT(FLAGS_OUTPUT_READY)) {
ctx->flags &= ~BIT(FLAGS_OUTPUT_READY);
if (test_and_clear_bit(FLAGS_OUTPUT_READY, &ctx->flags))
ready = 1;
}

if (dd->flags & BIT(FLAGS_DMA_ACTIVE)) {
dd->flags &= ~BIT(FLAGS_DMA_ACTIVE);
if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
omap_sham_update_dma_stop(dd);
if (!dd->err)
err = omap_sham_update_dma_start(dd);
Expand Down Expand Up @@ -1077,15 +1074,15 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}

if (unlikely(ctx->flags & BIT(FLAGS_FINAL)))
if (unlikely(test_bit(FLAGS_FINAL, &ctx->flags)))
/* final -> allow device to go to power-saving mode */
omap_sham_write_mask(dd, SHA_REG_CTRL, 0, SHA_REG_CTRL_LENGTH);

omap_sham_write_mask(dd, SHA_REG_CTRL, SHA_REG_CTRL_OUTPUT_READY,
SHA_REG_CTRL_OUTPUT_READY);
omap_sham_read(dd, SHA_REG_CTRL);

ctx->flags |= BIT(FLAGS_OUTPUT_READY);
set_bit(FLAGS_OUTPUT_READY, &ctx->flags);
dd->err = 0;
tasklet_schedule(&dd->done_task);

Expand All @@ -1099,7 +1096,7 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
if (ch_status != OMAP_DMA_BLOCK_IRQ) {
pr_err("omap-sham DMA error status: 0x%hx\n", ch_status);
dd->err = -EIO;
dd->flags &= ~BIT(FLAGS_INIT); /* request to re-initialize */
clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */
}

tasklet_schedule(&dd->done_task);
Expand Down

0 comments on commit a929cbe

Please sign in to comment.