Commit 04c848d3 authored by Thomas Gleixner's avatar Thomas Gleixner

genirq: Warn when IRQ_NOAUTOEN is used with shared interrupts

Shared interrupts do not go well with disabling auto enable:

1) The sharing interrupt might request it while it's still disabled and
   then wait for interrupts forever.

2) The interrupt might have been requested by the driver sharing the line
   before IRQ_NOAUTOEN has been set. So the driver which expects that
   disabled state after calling request_irq() will not get what it wants.
   Even worse, when it calls enable_irq() later, it will trigger the
   unbalanced enable_irq() warning.
Reported-by: default avatarBrian Norris <briannorris@chromium.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: dianders@chromium.org
Cc: jeffy <jeffy.chen@rock-chips.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: tfiga@chromium.org
Link: http://lkml.kernel.org/r/20170531100212.210682135@linutronix.de
parent 201d7f47
...@@ -935,6 +935,13 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) ...@@ -935,6 +935,13 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
if (!desc) if (!desc)
return; return;
/*
* Warn when a driver sets the no autoenable flag on an already
* active interrupt.
*/
WARN_ON_ONCE(!desc->depth && (set & _IRQ_NOAUTOEN));
irq_settings_clr_and_set(desc, clr, set); irq_settings_clr_and_set(desc, clr, set);
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
......
...@@ -1334,11 +1334,19 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) ...@@ -1334,11 +1334,19 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
if (new->flags & IRQF_ONESHOT) if (new->flags & IRQF_ONESHOT)
desc->istate |= IRQS_ONESHOT; desc->istate |= IRQS_ONESHOT;
if (irq_settings_can_autoenable(desc)) if (irq_settings_can_autoenable(desc)) {
irq_startup(desc, true); irq_startup(desc, true);
else } else {
/*
* Shared interrupts do not go well with disabling
* auto enable. The sharing interrupt might request
* it while it's still disabled and then wait for
* interrupts forever.
*/
WARN_ON_ONCE(new->flags & IRQF_SHARED);
/* Undo nested disables: */ /* Undo nested disables: */
desc->depth = 1; desc->depth = 1;
}
/* Exclude IRQ from balancing if requested */ /* Exclude IRQ from balancing if requested */
if (new->flags & IRQF_NOBALANCING) { if (new->flags & IRQF_NOBALANCING) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment