中断处理程序在完成一些堆栈和寄存器的处理后,调用do_IRQ函数。do_IRQ是中断在C语言的总入口。
common_interrupt:
addl $-0x80,(%esp) /* Adjust vector into the [-256,-1] range */
SAVE_ALL
TRACE_IRQS_OFF
movl %esp,%eax
call do_IRQ
jmp ret_from_intr
ENDPROC(common_interrupt)
CFI_ENDPROC
do_IRQ{)函数执行与一个中断相关的所有中断服务例程. 其原型如下:
unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
/* high bit used in ret_from_ code */
unsigned vector = ~regs->orig_ax;
unsigned irq;
exit_idle();
irq_enter(); //执行__irq_enter( )宏,它使表示中断处理程序嵌套数量的计数器递增.
irq = __get_cpu_var(vector_irq)[vector];//取得中断号
if (!handle_irq(irq, regs)) { //重要
ack_APIC_irq();
if (printk_ratelimit())
pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n",
__func__, smp_processor_id(), vector, irq);
}
irq_exit(); //重要
set_irq_regs(old_regs);
return 1;
}
bool handle_irq(unsigned irq, struct pt_regs *regs)
{
struct irq_desc *desc;
int overflow;
overflow = check_stack_overflow();
desc = irq_to_desc(irq); //根据中断号在数组irq_desc中找到一项
if (unlikely(!desc))
return false;
if (!execute_on_irq_stack(overflow, desc, irq)) {
if (unlikely(overflow))
print_stack_overflow();
desc->handle_irq(irq, desc);
}
return true;
desc
->
handle_irq初始化:
desc->handle_irq初始化发生在系统初始化时:
//linux-2.6.32/arch/x86/kernel/irqinit.c
void __init init_IRQ(void)
{
x86_init.irqs.intr_init();
}
//linux-2.6.32/arch/x86/kernel/x86_init.c
struct x86_init_ops x86_init __initdata = {
......
.irqs = {
.pre_vector_init = init_ISA_irqs, //被.intr_init调用
.intr_init = native_init_IRQ,
.trap_init = x86_init_noop,
},
......
}
//linux-2.6.32/arch/x86/kernel/irqinit.c
void __init native_init_IRQ(void)
{
......
/* Execute any quirks before the call gates are initialised: */
x86_init.irqs.pre_vector_init(); //init_ISA_irqs
......
}
void __init init_ISA_irqs(void)
{
......
for (i = 0; i < NR_IRQS_LEGACY; i++) {
......
set_irq_chip_and_handler_name(i, &i8259A_chip,
handle_level_irq, "XT");
}
}
void
set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
irq_flow_handler_t handle, const char *name)
{
set_irq_chip(irq, chip);
__set_irq_handler(irq, handle, 0, name);
}
void __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)
{
....
desc->handle_irq = handle;//handle 即为handle_level_irq
....
}
可见desc->handle_irq(irq, desc);执行的是handle_level_irq
(irq, desc)。
我们进入handle_level_irq(irq, desc)可靠desc->handle_irq(irq, description)做了哪些操作:
void handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
mask_ack_irq(desc, irq); //屏蔽中断
......
action = desc->action;
action_ret = handle_IRQ_event(irq, action);
......
desc->chip->unmask(irq); //打开中断
}
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
......
do {
ret = action->handler(irq, action->dev_id);//指向我们注册的中断处理函数
......
} while (action);
.....
}
action->handler中断处理函数是通过irq申请函数
can_request_irq/request_irq
注册的。
回到do_IRQ
最后执行了
irq_exit();
void irq_exit(void)
{
account_system_vtime(current);
trace_hardirq_exit();
sub_preempt_count(IRQ_EXIT_OFFSET);
if (!in_interrupt() && local_softirq_pending())
invoke_softirq(); //调用软irq处理
#ifdef CONFIG_NO_HZ
/* Make sure that timer wheel updates are propagated */
rcu_irq_exit();
if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
tick_nohz_stop_sched_tick(0);
#endif
preempt_enable_no_resched();
}