diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-09 16:25:11 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-11-09 16:25:10 -0800 |
commit | e95375540c79e0d0b48953141559fec4b6bcbf96 (patch) | |
tree | 9d3dad415e729c9cb0a6ffe472cfc84b2db66d62 | |
parent | 05a0fa2b206786b5bed2bc7098acd82cae63334d (diff) | |
parent | 8ae62993fc66b919369ca85d587117f277cf7001 (diff) |
Merge "crypto: msm: qce50: Prevent deadlock during timeout"
-rw-r--r-- | drivers/crypto/msm/qce50.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 3562de7fc967..55c043b44cea 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -3023,6 +3023,7 @@ static void qce_multireq_timeout(unsigned long data) struct qce_device *pce_dev = (struct qce_device *)data; int ret = 0; int last_seq; + unsigned long flags; last_seq = atomic_read(&pce_dev->bunch_cmd_seq); if (last_seq == 0 || @@ -3032,21 +3033,33 @@ static void qce_multireq_timeout(unsigned long data) return; } /* last bunch mode command time out */ + + /* + * From here to dummy request finish sps request and set owner back + * to none, we disable interrupt. + * So it won't get preempted or interrupted. If bam inerrupts happen + * between, and completion callback gets called from BAM, a new + * request may be issued by the client driver. Deadlock may happen. + */ + local_irq_save(flags); if (cmpxchg(&pce_dev->owner, QCE_OWNER_NONE, QCE_OWNER_TIMEOUT) != QCE_OWNER_NONE) { + local_irq_restore(flags); mod_timer(&(pce_dev->timer), (jiffies + DELAY_IN_JIFFIES)); return; } - del_timer(&(pce_dev->timer)); - pce_dev->mode = IN_INTERRUPT_MODE; - pce_dev->qce_stats.no_of_timeouts++; - pr_debug("pcedev %d mode switch to INTR\n", pce_dev->dev_no); ret = qce_dummy_req(pce_dev); if (ret) pr_warn("pcedev %d: Failed to insert dummy req\n", pce_dev->dev_no); cmpxchg(&pce_dev->owner, QCE_OWNER_TIMEOUT, QCE_OWNER_NONE); + pce_dev->mode = IN_INTERRUPT_MODE; + local_irq_restore(flags); + + del_timer(&(pce_dev->timer)); + pce_dev->qce_stats.no_of_timeouts++; + pr_debug("pcedev %d mode switch to INTR\n", pce_dev->dev_no); } void qce_get_driver_stats(void *handle) |