summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2016-09-13 09:58:29 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-09-13 10:57:40 -0400
commit5eb0d6eb3fac3daa60d9190eed9fa41cf809c756 (patch)
tree08d2a2d7653f2c8aa91947fef325065855502b2d
parentebf9ff753c041b296241990aef76163bbb2cc9c8 (diff)
irqchip/atmel-aic: Fix potential deadlock in ->xlate()
aic5_irq_domain_xlate() and aic_irq_domain_xlate() take the generic chip lock without disabling interrupts, which can lead to a deadlock if an interrupt occurs while the lock is held in one of these functions. Replace irq_gc_{lock,unlock}() calls by irq_gc_{lock_irqsave,unlock_irqrestore}() ones to prevent this bug from happening. Fixes: b1479ebb7720 ("irqchip: atmel-aic: Add atmel AIC/AIC5 drivers") Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: stable@vger.kernel.org Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com> Link: http://lkml.kernel.org/r/1473775109-4192-2-git-send-email-boris.brezillon@free-electrons.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/irqchip/irq-atmel-aic.c5
-rw-r--r--drivers/irqchip/irq-atmel-aic5.c5
2 files changed, 6 insertions, 4 deletions
diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c
index 112e17c2768b..37f952dd9fc9 100644
--- a/drivers/irqchip/irq-atmel-aic.c
+++ b/drivers/irqchip/irq-atmel-aic.c
@@ -176,6 +176,7 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
176{ 176{
177 struct irq_domain_chip_generic *dgc = d->gc; 177 struct irq_domain_chip_generic *dgc = d->gc;
178 struct irq_chip_generic *gc; 178 struct irq_chip_generic *gc;
179 unsigned long flags;
179 unsigned smr; 180 unsigned smr;
180 int idx; 181 int idx;
181 int ret; 182 int ret;
@@ -194,11 +195,11 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
194 195
195 gc = dgc->gc[idx]; 196 gc = dgc->gc[idx];
196 197
197 irq_gc_lock(gc); 198 irq_gc_lock_irqsave(gc, flags);
198 smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq)); 199 smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
199 aic_common_set_priority(intspec[2], &smr); 200 aic_common_set_priority(intspec[2], &smr);
200 irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq)); 201 irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
201 irq_gc_unlock(gc); 202 irq_gc_unlock_irqrestore(gc, flags);
202 203
203 return ret; 204 return ret;
204} 205}
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c
index 4f0d068e1abe..2a624d87a035 100644
--- a/drivers/irqchip/irq-atmel-aic5.c
+++ b/drivers/irqchip/irq-atmel-aic5.c
@@ -258,6 +258,7 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
258 unsigned int *out_type) 258 unsigned int *out_type)
259{ 259{
260 struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0); 260 struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0);
261 unsigned long flags;
261 unsigned smr; 262 unsigned smr;
262 int ret; 263 int ret;
263 264
@@ -269,12 +270,12 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
269 if (ret) 270 if (ret)
270 return ret; 271 return ret;
271 272
272 irq_gc_lock(bgc); 273 irq_gc_lock_irqsave(bgc, flags);
273 irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR); 274 irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR);
274 smr = irq_reg_readl(bgc, AT91_AIC5_SMR); 275 smr = irq_reg_readl(bgc, AT91_AIC5_SMR);
275 aic_common_set_priority(intspec[2], &smr); 276 aic_common_set_priority(intspec[2], &smr);
276 irq_reg_writel(bgc, smr, AT91_AIC5_SMR); 277 irq_reg_writel(bgc, smr, AT91_AIC5_SMR);
277 irq_gc_unlock(bgc); 278 irq_gc_unlock_irqrestore(bgc, flags);
278 279
279 return ret; 280 return ret;
280} 281}