ARM: 6532/1: Allow machine to specify it's own IRQ handlers at run-time
authoreric miao <eric.y.miao@gmail.com>
Mon, 13 Dec 2010 08:42:34 +0000 (09:42 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 24 Dec 2010 09:47:34 +0000 (09:47 +0000)
Normally different ARM platform has different way to decode the IRQ
hardware status and demultiplex to the corresponding IRQ handler.
This is highly optimized by macro irq_handler in entry-armv.S, and
each machine defines their own macro to decode the IRQ number.
However, this prevents multiple machine classes to be built into a
single kernel.

By allowing each machine to specify thier own handler, and making
function pointer 'handle_arch_irq' to point to it at run time, this
can be solved. And introduce CONFIG_MULTI_IRQ_HANDLER to allow both
solutions to work.

Comparing with the highly optimized macro of irq_handler, the new
function must be written with care not to lose too much performance.
And the IPI stuff on SMP is expected to move to the provided arch
IRQ handler as well.

The assembly code to invoke handle_arch_irq is optimized by Russell
King.

Signed-off-by: Eric Miao <eric.miao@canonical.com>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/mach/irq.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/setup.c

index fd0e21be5e4401c70259a5076260d7b805ba9c6d..47694865018c445cf47109ecedf0b10b32048474 100644 (file)
@@ -1022,6 +1022,11 @@ config CPU_HAS_PMU
        default y
        bool
 
+config MULTI_IRQ_HANDLER
+       bool
+       help
+         Allow each machine to specify it's own IRQ handler at run time.
+
 if !MMU
 source "arch/arm/Kconfig-nommu"
 endif
index d97a964207fa15693c011f88f27dc64f4c7c3f16..7d55356110d48264270b72362d915b7d4078c645 100644 (file)
@@ -40,6 +40,9 @@ struct machine_desc {
        void                    (*init_irq)(void);
        struct sys_timer        *timer;         /* system tick timer    */
        void                    (*init_machine)(void);
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       void                    (*handle_irq)(struct pt_regs *);
+#endif
 };
 
 /*
index ce3eee9fe26cbb055cbea6ab0d5567af4964b29a..6ecdad9a5c42a4eb453ff086ec8f95e4edada8e0 100644 (file)
@@ -22,6 +22,10 @@ extern void (*init_arch_irq)(void);
 extern void init_FIQ(void);
 extern int show_fiq_list(struct seq_file *, void *);
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+extern void (*handle_arch_irq)(struct pt_regs *);
+#endif
+
 /*
  * This is for easy migration, but should be changed in the source
  */
index 35f3f20d6731892300d6417f08d4a14b869720d0..caa6c396ec78433733da3db0c9e47bdc623959ae 100644 (file)
  * Interrupt handling.  Preserves r7, r8, r9
  */
        .macro  irq_handler
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       ldr     r5, =handle_arch_irq
+       mov     r0, sp
+       ldr     r5, [r5]
+       adr     lr, BSYM(9997f)
+       teq     r5, #0
+       movne   pc, r5
+#endif
        get_irqnr_preamble r5, lr
 1:     get_irqnr_and_base r0, r6, r5, lr
        movne   r1, sp
@@ -58,9 +66,8 @@
        adrne   lr, BSYM(1b)
        bne     do_local_timer
 #endif
-9997:
 #endif
-
+9997:
        .endm
 
 #ifdef CONFIG_KPROBES
@@ -1245,3 +1252,9 @@ cr_alignment:
        .space  4
 cr_no_alignment:
        .space  4
+
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       .globl  handle_arch_irq
+handle_arch_irq:
+       .space  4
+#endif
index 8075e592f902ff6f0def0546d85fe34783ae0b53..0826f36330c463f5bbe99c0065f58f903a7a833d 100644 (file)
@@ -875,6 +875,9 @@ void __init setup_arch(char **cmdline_p)
        init_arch_irq = mdesc->init_irq;
        system_timer = mdesc->timer;
        init_machine = mdesc->init_machine;
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+       handle_arch_irq = mdesc->handle_irq;
+#endif
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)