2012-10-20 luoqindong
使用phy3250开发板.
LPC3250中断处理流程:
1.跳到中断向量vector_irq
arch\arm\kernel\entry-armv.S
.globl
__vectors_start
__vectors_start:
swi
SYS_ERROR0
b
vector_und + stubs_offset
ldr
pc, .LCvswi + stubs_offset
b
vector_pabt + stubs_offset
b
vector_dabt + stubs_offset
b
vector_addrexcptn + stubs_offset
b
vector_irq + stubs_offset
b
vector_fiq + stubs_offset
.globl
__vectors_end
__vectors_end:
2.从vector_irq跳到__irq_usr(在用户模式中断的时候)或__irq_svc(在管理模式中断的时候)
/*
* Interrupt dispatcher
*/
vector_stub
irq, IRQ_MODE, 4
.long
__irq_usr
@ 0 (USR_26 / USR_32)
.long
__irq_invalid
@ 1 (FIQ_26 / FIQ_32)
.long
__irq_invalid
@ 2 (IRQ_26 / IRQ_32)
.long
__irq_svc
@ 3 (SVC_26 / SVC_32)
.long
__irq_invalid
@ 4
.long
__irq_invalid
@ 5
.long
__irq_invalid
@ 6
.long
__irq_invalid
@ 7
.long
__irq_invalid
@ 8
.long
__irq_invalid
@ 9
.long
__irq_invalid
@ a
.long
__irq_invalid
@ b
.long
__irq_invalid
@ c
.long
__irq_invalid
@ d
.long
__irq_invalid
@ e
.long
__irq_invalid
@ f
3.从__irq_usr或__irq_svc跳到irq_handler
.align
5
__irq_usr:
usr_entry
kuser_cmpxchg_check
#ifdef CONFIG_TRACE_IRQFLAGS
bl
trace_hardirqs_off
#endif
get_thread_info tsk
#ifdef CONFIG_PREEMPT
ldr
r8, [tsk, #TI_PREEMPT]
@ get preempt count
add
r7, r8, #1
@ increment it
str
r7, [tsk, #TI_PREEMPT]
#endif
irq_handler
#ifdef CONFIG_PREEMPT
ldr
r0, [tsk, #TI_PREEMPT]
str
r8, [tsk, #TI_PREEMPT]
teq
r0, r7
strne
r0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl
trace_hardirqs_on
#endif
mov
why, #0
b
ret_to_user
irq_handler是宏,跳到asm_do_IRQ
/*
* Interrupt handling. Preserves r7, r8, r9
*/
.macro
irq_handler
get_irqnr_preamble r5, lr
1:
get_irqnr_and_base r0, r6, r5, lr
movne
r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne
lr, 1b
bne
asm_do_IRQ
#ifdef CONFIG_SMP
/*
* XXX
*
* this macro assumes that irqstat (r6) and base (r5) are
* preserved from get_irqnr_and_base above
*/
test_for_ipi r0, r6, r5, lr
movne
r0, sp
adrne
lr, 1b
bne
do_IPI
#ifdef CONFIG_LOCAL_TIMERS
test_for_ltirq r0, r6, r5, lr
movne
r0, sp
adrne
lr, 1b
bne
do_local_timer
#endif
#endif
.endm
4.asm_do_IRQ在arch\arm\kernel\irq.c中定义:
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc = irq_desc + irq;
/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (irq >= NR_IRQS)
desc = &bad_irq_desc;
irq_enter();
desc_handle_irq(irq, desc);
/* AT91 specific workaround */
irq_finish(irq);
irq_exit();
set_irq_regs(old_regs);
}
5.desc_handle_irq在arch\arm\include\asm\hw_irq.h中定义:
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
desc->handle_irq(irq, desc);
}
6.handle_irq在arch\arm\mach-lpc32xx\irq-lpc32xx.c--lpc32xx_init_irq函数中初始化
/* Set default mappings */
lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, INTC_SIC1_OFFS);
lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, INTC_SIC2_OFFS);
lpc32xx_set_default_mappings->lpc32xx_set_irq_type->set_irq_handler(irq, handle_edge_irq)->__set_irq_handler
set_irq_handler和__set_irq_handler在include\linux\irq.h中定义.
handle_irq被赋值为:
handle_level_irq或handle_edge_irq,这两个函数最后会调用request_irq传进去的中断处理函数.