Hi Thomas/lkml,
setup_irq() code contains a big chunk of 130 code lines that
can be divided to several smaller methods. These 2 patches introduce
those small functions to aid toward setup_irq() code modularity.
No major code logic changes exist.
Patches can be applied cleanly over v2.6.23-rc9.
Thanks,
==> (Description for Logs)
Introduce can_add_irqaction_on_allocated_irq and warn_about_irqaction_mismatch
methods to support setup_irq() code modularity.
Signed-off-by: Ahmed S. Darwish <[email protected]>
---
manage.c | 92 +++++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 55 insertions(+), 37 deletions(-)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 7230d91..6a0d778 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -248,6 +248,50 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
desc->handle_irq = NULL;
}
+static inline void warn_about_irqaction_mismatch(unsigned int irq,
+ struct irqaction *new)
+{
+#ifdef CONFIG_DEBUG_SHIRQ
+ const char *name = irq_desc[irq].action->name;
+ /* If device doesn't expect the mismatch */
+ if (!(new->flags & IRQF_PROBE_SHARED)) {
+ printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
+ if (name)
+ printk(KERN_ERR "current handler: %s\n", name);
+ dump_stack();
+ }
+#endif
+}
+
+/*
+ * Test if an irqaction can be added to the passed allocated IRQ line
+ * Must be called with the irq_desc[irq]->lock held.
+ */
+int can_add_irqaction_on_allocated_irq(unsigned int irq, struct irqaction *new)
+{
+ struct irqaction *old = irq_desc[irq].action;
+
+ BUG_ON(!old);
+ /*
+ * 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.
+ */
+ if (!((old->flags & new->flags) & IRQF_SHARED) ||
+ ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK))
+ return 0;
+
+#if defined(CONFIG_IRQ_PER_CPU)
+ /* All handlers must agree on per-cpuness */
+ if ((old->flags & IRQF_PERCPU) !=
+ (new->flags & IRQF_PERCPU))
+ return 0;
+#endif
+
+ return 1;
+}
+
/*
* Internal function to register an irqaction - typically used to
* allocate special interrupts that are part of the architecture.
@@ -256,7 +300,6 @@ int setup_irq(unsigned int irq, struct irqaction *new)
{
struct irq_desc *desc = irq_desc + irq;
struct irqaction *old, **p;
- const char *old_name = NULL;
unsigned long flags;
int shared = 0;
@@ -289,31 +332,18 @@ int setup_irq(unsigned int irq, struct irqaction *new)
p = &desc->action;
old = *p;
if (old) {
- /*
- * 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.
- */
- if (!((old->flags & new->flags) & IRQF_SHARED) ||
- ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
- old_name = old->name;
- goto mismatch;
- }
-
-#if defined(CONFIG_IRQ_PER_CPU)
- /* All handlers must agree on per-cpuness */
- if ((old->flags & IRQF_PERCPU) !=
- (new->flags & IRQF_PERCPU))
- goto mismatch;
-#endif
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
shared = 1;
+ if (can_add_irqaction_on_allocated_irq(irq, new)) {
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ } else {
+ warn_about_irqaction_mismatch(irq, new);
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return -EBUSY;
+ }
}
*p = new;
@@ -372,18 +402,6 @@ int setup_irq(unsigned int irq, struct irqaction *new)
register_handler_proc(irq, new);
return 0;
-
-mismatch:
-#ifdef CONFIG_DEBUG_SHIRQ
- if (!(new->flags & IRQF_PROBE_SHARED)) {
- printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
- if (old_name)
- printk(KERN_ERR "current handler: %s\n", old_name);
- dump_stack();
- }
-#endif
- spin_unlock_irqrestore(&desc->lock, flags);
- return -EBUSY;
}
/**
--
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com
Introduce irq_desc_match_fist_irqaction() to support setup_irq()
code modularity.
Signed-off-by: Ahmed S. Darwish <[email protected]>
---
Any ideas for a better method name ?
manage.c | 89 ++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 51 insertions(+), 38 deletions(-)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 6a0d778..4e96d56 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -293,6 +293,55 @@ int can_add_irqaction_on_allocated_irq(unsigned int irq, struct irqaction *new)
}
/*
+ * Configure the passed irq descriptor to satisfy our first newly
+ * added irqaction needs
+ * must be called with the irq_desc[irq]->lock held
+ */
+void irq_desc_match_fist_irqaction(unsigned int irq, struct irqaction *new)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ /* We must be the first and the only irqaction */
+ BUG_ON(desc->action != new || new->next);
+
+ irq_chip_set_defaults(desc->chip);
+
+#if defined(CONFIG_IRQ_PER_CPU)
+ if (new->flags & IRQF_PERCPU)
+ desc->status |= IRQ_PER_CPU;
+#endif
+
+ /* Setup the type (level, edge polarity) if configured: */
+ if (new->flags & IRQF_TRIGGER_MASK) {
+ if (desc->chip && desc->chip->set_type)
+ desc->chip->set_type(irq,
+ new->flags & IRQF_TRIGGER_MASK);
+ else
+ /*
+ * IRQF_TRIGGER_* but the PIC does not support
+ * multiple flow-types?
+ */
+ printk(KERN_WARNING "No IRQF_TRIGGER set_type "
+ "function for IRQ %d (%s)\n", irq,
+ desc->chip ? desc->chip->name : "unknown");
+ } else
+ compat_irq_chip_set_default_handler(desc);
+
+ desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+
+ if (!(desc->status & IRQ_NOAUTOEN)) {
+ desc->depth = 0;
+ desc->status &= ~IRQ_DISABLED;
+ if (desc->chip->startup)
+ desc->chip->startup(irq);
+ else
+ desc->chip->enable(irq);
+ } else
+ /* Undo nested disables: */
+ desc->depth = 1;
+}
+
+/*
* Internal function to register an irqaction - typically used to
* allocate special interrupts that are part of the architecture.
*/
@@ -352,45 +401,9 @@ int setup_irq(unsigned int irq, struct irqaction *new)
if (new->flags & IRQF_NOBALANCING)
desc->status |= IRQ_NO_BALANCING;
- if (!shared) {
- irq_chip_set_defaults(desc->chip);
+ if (!shared)
+ irq_desc_match_fist_irqaction(irq, new);
-#if defined(CONFIG_IRQ_PER_CPU)
- if (new->flags & IRQF_PERCPU)
- desc->status |= IRQ_PER_CPU;
-#endif
-
- /* Setup the type (level, edge polarity) if configured: */
- if (new->flags & IRQF_TRIGGER_MASK) {
- if (desc->chip && desc->chip->set_type)
- desc->chip->set_type(irq,
- new->flags & IRQF_TRIGGER_MASK);
- else
- /*
- * IRQF_TRIGGER_* but the PIC does not support
- * multiple flow-types?
- */
- printk(KERN_WARNING "No IRQF_TRIGGER set_type "
- "function for IRQ %d (%s)\n", irq,
- desc->chip ? desc->chip->name :
- "unknown");
- } else
- compat_irq_chip_set_default_handler(desc);
-
- desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
- IRQ_INPROGRESS);
-
- if (!(desc->status & IRQ_NOAUTOEN)) {
- desc->depth = 0;
- desc->status &= ~IRQ_DISABLED;
- if (desc->chip->startup)
- desc->chip->startup(irq);
- else
- desc->chip->enable(irq);
- } else
- /* Undo nested disables: */
- desc->depth = 1;
- }
/* Reset broken irq detection when installing new handler */
desc->irq_count = 0;
desc->irqs_unhandled = 0;
--
Ahmed S. Darwish
HomePage: http://darwish.07.googlepages.com
Blog: http://darwish-07.blogspot.com