Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: fsl: qbman: avoid race in clearing QMan interrupt

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>

authored by

Madalin Bucur and committed by
Li Yang
89857a8a bfeffd15

+5 -4
+5 -4
drivers/soc/fsl/qbman/qman.c
··· 1143 1143 static irqreturn_t portal_isr(int irq, void *ptr) 1144 1144 { 1145 1145 struct qman_portal *p = ptr; 1146 - 1147 - u32 clear = QM_DQAVAIL_MASK | p->irq_sources; 1148 1146 u32 is = qm_in(&p->p, QM_REG_ISR) & p->irq_sources; 1147 + u32 clear = 0; 1149 1148 1150 1149 if (unlikely(!is)) 1151 1150 return IRQ_NONE; 1152 1151 1153 1152 /* DQRR-handling if it's interrupt-driven */ 1154 - if (is & QM_PIRQ_DQRI) 1153 + if (is & QM_PIRQ_DQRI) { 1155 1154 __poll_portal_fast(p, QMAN_POLL_LIMIT); 1155 + clear = QM_DQAVAIL_MASK | QM_PIRQ_DQRI; 1156 + } 1156 1157 /* Handling of anything else that's interrupt-driven */ 1157 - clear |= __poll_portal_slow(p, is); 1158 + clear |= __poll_portal_slow(p, is) & QM_PIRQ_SLOW; 1158 1159 qm_out(&p->p, QM_REG_ISR, clear); 1159 1160 return IRQ_HANDLED; 1160 1161 }