linux kernel 工程师
全部博文(99)
分类: LINUX
2014-02-08 15:37:08
在x86里面irq的入口函数是 do_irq()
在arm里面irq的入口函数是 asm_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;
irq_enter();
exit_idle();
irq = __this_cpu_read(vector_irq[vector]);
msa_start_irq(irq);
if (!handle_irq(irq, regs)) {
/* handle_irq最终会调用desc->handle_irq,desc->handle_irq最后又会调用handle_irq_event,
handle_irq_event 又会调用desc->action->handler, 并根据返回结果
1. IRQ_WAKE_THREAD 通常是线程化的中断,这时需要唤醒该中断对应的内核线程
2. IRQ_HANDLED 表示中断已经处理完毕,通常是非线程化的中断返回该值
*/
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);
}
msa_irq_exit(irq, regs->cs != __KERNEL_CS);
set_irq_regs(old_regs);
return 1;
}
handle_irq在x86_64 与x86_32中有不同的实现,但最终都是要调用desc->handle_irq
-----------------------handle_irq在x86_64的实现--------------------------
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
desc->handle_irq(irq, desc);
}
arch\x86\kernel\irq_64.c
bool handle_irq(unsigned irq, struct pt_regs *regs)
{
struct irq_desc *desc;
stack_overflow_check(regs);
desc = irq_to_desc(irq);
if (unlikely(!desc))
return false;
generic_handle_irq_desc(irq, desc);
return true;
}
-----------------------handle_irq在x86_32的实现--------------------------
bool handle_irq(unsigned irq, struct pt_regs *regs)
{
struct irq_desc *desc;
int overflow;
overflow = check_stack_overflow();
desc = irq_to_desc(irq);
if (unlikely(!desc))
return false;
if (user_mode_vm(regs) /* 如果在执行用户态代码时,发生中断,切换到内核态,内核态栈是空的,所以不需要切换的中断栈 */
|| !execute_on_irq_stack(overflow, desc, irq)) {
/* execute_on_irq_stack实现从内核栈到中断栈的切换
如果已经在中断栈了,则不用切换,返回0,执行下面的desc->handle_irq
如果不在中断栈,切换到中断栈,并且在中断栈上执行desc->handle_irq, 返回1,下面的desc->handle_irq不会再执行*/
if (unlikely(overflow))
print_stack_overflow();
desc->handle_irq(irq, desc);
}
return true;
}