summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-11-09 16:25:11 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-09 16:25:10 -0800
commite95375540c79e0d0b48953141559fec4b6bcbf96 (patch)
tree9d3dad415e729c9cb0a6ffe472cfc84b2db66d62
parent05a0fa2b206786b5bed2bc7098acd82cae63334d (diff)
parent8ae62993fc66b919369ca85d587117f277cf7001 (diff)
Merge "crypto: msm: qce50: Prevent deadlock during timeout"
-rw-r--r--drivers/crypto/msm/qce50.c21
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)