[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20070726201355.GP19275@parisc-linux.org>
Date: Thu, 26 Jul 2007 14:13:56 -0600
From: Matthew Wilcox <matthew@....cx>
To: Ingo Molnar <mingo@...e.hu>, linux-kernel@...r.kernel.org
Cc: Linus Torvalds <torvalds@...l.org>
Subject: IRQF_DISABLED problem
I noticed that we only look at the first action in the chain when
determining whether to re-enable local interrupts during handle_IRQ_event.
But we don't try to exclude sharing interrupts with mixtures of
IRQF_DISABLED set and clear. I just tried to do that locally, and one
of my USB ports disappears, because it shares an interrupt with qla2xxx
which sets IRQF_DISABLED, and UHCI doesn't.
Another possibility is to force it if *any* of the handlers want
IRQF_DISABLED. This seems to work:
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 203a518..d804a0b 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -308,6 +308,15 @@ int setup_irq(unsigned int irq, struct irqaction *new)
goto mismatch;
#endif
+ /* If one handler wants interrupts to be disabled,
+ * they must all be disabled. Rather than walk the list of
+ * handlers twice at interrupt time, just make sure the
+ * head handler has its flag set
+ */
+ if ((new->flags & IRQF_DISABLED) &&
+ !(old->flags & IRQF_DISABLED)
+ old->flags |= IRQF_DISABLED);
+
/* add new interrupt at end of irq queue */
do {
p = &old->next;
This patch makes interrupts requested with IRQF_DISABLED non-matching
fail, in case you think it's a better solution:
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 203a518..2c99b88 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -293,10 +293,12 @@ int setup_irq(unsigned int irq, struct irqaction *new)
* Can't share interrupts unless both agree to and are
* the same type (level, edge, polarity). So both flag
* fields must have IRQF_SHARED set and the bits which
- * set the trigger type must match.
+ * set the trigger type must match and the disabled bit
+ * must match.
*/
if (!((old->flags & new->flags) & IRQF_SHARED) ||
- ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
+ ((old->flags ^ new->flags) &
+ (IRQF_TRIGGER_MASK | IRQF_DISABLED))) {
old_name = old->name;
goto mismatch;
}
--
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists