[PATCH] genirq: core

Core genirq support: add the irq-chip and irq-flow abstractions.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
index ed98c7d..cfdb63e 100644
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -40,8 +40,15 @@
 		desc = irq_desc + i;
 
 		spin_lock_irq(&desc->lock);
-		if (!desc->action && !(desc->status & IRQ_NOPROBE))
+		if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
+			/*
+			 * Some chips need to know about probing in
+			 * progress:
+			 */
+			if (desc->chip->set_type)
+				desc->chip->set_type(i, IRQ_TYPE_PROBE);
 			desc->chip->startup(i);
+		}
 		spin_unlock_irq(&desc->lock);
 	}
 
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index bddcb8f..a04b516 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -18,6 +18,16 @@
 
 #include "internals.h"
 
+/**
+ * handle_bad_irq - handle spurious and unhandled irqs
+ */
+void fastcall
+handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+	kstat_this_cpu.irqs[irq]++;
+	ack_bad_irq(irq);
+}
+
 /*
  * Linux has a controller-independent interrupt architecture.
  * Every controller has a 'controller-template', that is used
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 46feba6..2ba8ae3 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -4,6 +4,12 @@
 
 extern int noirqdebug;
 
+/* Set default functions for irq_chip structures: */
+extern void irq_chip_set_defaults(struct irq_chip *chip);
+
+/* Set default handler: */
+extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
+
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq);
 extern void register_handler_proc(unsigned int irq, struct irqaction *action);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 1a2e766..b61784e 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -153,6 +153,17 @@
 	return !action;
 }
 
+void compat_irq_chip_set_default_handler(struct irq_desc *desc)
+{
+	/*
+	 * If the architecture still has not overriden
+	 * the flow handler then zap the default. This
+	 * should catch incorrect flow-type setting.
+	 */
+	if (desc->handle_irq == &handle_bad_irq)
+		desc->handle_irq = NULL;
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -217,6 +228,9 @@
 		desc->status |= IRQ_PER_CPU;
 #endif
 	if (!shared) {
+		irq_chip_set_defaults(desc->chip);
+		compat_irq_chip_set_default_handler(desc);
+
 		desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
 				  IRQ_INPROGRESS);
 
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
index 096b102..872f91b 100644
--- a/kernel/irq/resend.c
+++ b/kernel/irq/resend.c
@@ -37,9 +37,9 @@
 		irq = find_first_bit(irqs_resend, NR_IRQS);
 		clear_bit(irq, irqs_resend);
 		desc = irq_desc + irq;
-		spin_lock_irqsave(&desc->lock, flags);
+		local_irq_disable();
 		desc->handle_irq(irq, desc, NULL);
-		spin_unlock_irqrestore(&desc->lock, flags);
+		local_irq_enable();
 	}
 }
 
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 3a0a621..ca187b8 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -168,6 +168,7 @@
 		 */
 		printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
 		desc->status |= IRQ_DISABLED;
+		desc->depth = 1;
 		desc->chip->disable(irq);
 	}
 	desc->irqs_unhandled = 0;