summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMadalin Bucur <madalin.bucur@nxp.com>2018-12-21 16:41:42 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-03-13 14:04:58 -0700
commitd31765ea42565bec01b1319c2a750a1d502e731a (patch)
tree0b3f45bd6f8ae5c01276f30a1b9ad67241bfff6d /drivers
parent37b6ac5254e6f16823b81e94173c603fd0e8a70a (diff)
soc: fsl: qbman: avoid race in clearing QMan interrupt
[ Upstream commit 89857a8a5c89a406b967ab2be7bd2ccdbe75e73d ] By clearing all interrupt sources, not only those that already occurred, the existing code may acknowledge by mistake interrupts that occurred after the code checks for them. Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com> Signed-off-by: Roy Pledge <roy.pledge@nxp.com> Signed-off-by: Li Yang <leoyang.li@nxp.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/soc/fsl/qbman/qman.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 2cc82ed6433a..91f5c951850f 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1073,18 +1073,19 @@ static void qm_mr_process_task(struct work_struct *work);
static irqreturn_t portal_isr(int irq, void *ptr)
{
struct qman_portal *p = ptr;
-
- u32 clear = QM_DQAVAIL_MASK | p->irq_sources;
u32 is = qm_in(&p->p, QM_REG_ISR) & p->irq_sources;
+ u32 clear = 0;
if (unlikely(!is))
return IRQ_NONE;
/* DQRR-handling if it's interrupt-driven */
- if (is & QM_PIRQ_DQRI)
+ if (is & QM_PIRQ_DQRI) {
__poll_portal_fast(p, QMAN_POLL_LIMIT);
+ clear = QM_DQAVAIL_MASK | QM_PIRQ_DQRI;
+ }
/* Handling of anything else that's interrupt-driven */
- clear |= __poll_portal_slow(p, is);
+ clear |= __poll_portal_slow(p, is) & QM_PIRQ_SLOW;
qm_out(&p->p, QM_REG_ISR, clear);
return IRQ_HANDLED;
}