فهرست منبع

ARM: 6532/1: Allow machine to specify it's own IRQ handlers at run-time

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>
eric miao 14 سال پیش
والد
کامیت
521086412e
5فایلهای تغییر یافته به همراه30 افزوده شده و 2 حذف شده
  1. 5 0
      arch/arm/Kconfig
  2. 3 0
      arch/arm/include/asm/mach/arch.h
  3. 4 0
      arch/arm/include/asm/mach/irq.h
  4. 15 2
      arch/arm/kernel/entry-armv.S
  5. 3 0
      arch/arm/kernel/setup.c

+ 5 - 0
arch/arm/Kconfig

@@ -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

+ 3 - 0
arch/arm/include/asm/mach/arch.h

@@ -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
 };
 
 /*

+ 4 - 0
arch/arm/include/asm/mach/irq.h

@@ -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
  */

+ 15 - 2
arch/arm/kernel/entry-armv.S

@@ -30,6 +30,14 @@
  * 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

+ 3 - 0
arch/arm/kernel/setup.c

@@ -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)