linux 中断处理流程

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传进去的中断处理函数.



你可能感兴趣的:(thread,linux,exception,vector,struct,include)