中断详解(六)——do_IRQ函数
时间:2015-03-25 12:12:09
收藏:0
阅读:577
中断处理程序在完成一些堆栈和寄存器的处理后,调用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_ENDPROCdo_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(); }
原文:http://blog.csdn.net/windeal3203/article/details/44594783
评论(0)