diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-09-13 09:58:29 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-09-13 10:57:40 -0400 |
commit | 5eb0d6eb3fac3daa60d9190eed9fa41cf809c756 (patch) | |
tree | 08d2a2d7653f2c8aa91947fef325065855502b2d | |
parent | ebf9ff753c041b296241990aef76163bbb2cc9c8 (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.c | 5 | ||||
-rw-r--r-- | drivers/irqchip/irq-atmel-aic5.c | 5 |
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 | } |