linux-2.6.20 /usr/src/linux/include/asm-x86_64/hw_irq.h +122 --------------------------------------------- #define BUILD_IRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ __asm__( \ "\n.p2align\n" \ "IRQ" #nr "_interrupt:\n\t" \ "push $~(" #nr ") ; " \ "jmp common_interrupt");
/usr/src/linux/arch/i386/kernel/entry.S +206 --------------------------------------------- common_interrupt: SAVE_ALL TRACE_IRQS_OFF movl %esp,%eax call do_IRQ jmp ret_from_intr CFI_ENDPROC
handle_fasteoi_irq() handle_edge_irq() common_interrupt: --> do_IRQ() --> handle_irq() --> handle_IRQ_event() --> action->handler()
do_IRQ() -- 中断机制入口函数
common_interrupt --> do_IRQ()
linux-2.6.20 vi /usr/src/linux/arch/i386/kernel/irq.c +54 --------------------------------------------- astcall unsigned int do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs; int irq = ~regs->orig_eax; struct irq_desc *desc = irq_desc + irq; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; u32 *isp; #endif if (unlikely((unsigned)irq >= NR_IRQS)) { printk(KERN_EMERG "%s: cannot handle IRQ %d\n", __FUNCTION__, irq); BUG(); } old_regs = set_irq_regs(regs);
增加中断处理程序的嵌套计数 |-------------------| | irq_enter(); | |-------------------|
#ifdef CONFIG_DEBUG_STACKOVERFLOW { long esp; __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (THREAD_SIZE - 1)); if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) { printk("do_IRQ: stack overflow: %ld\n", esp - sizeof(struct thread_info)); dump_stack(); } } #endif
#ifdef CONFIG_4KSTACKS curctx = (union irq_ctx *) current_thread_info(); irqctx = hardirq_ctx[smp_processor_id()]; if (curctx != irqctx) { int arg1, arg2, ebx; isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); irqctx->tinfo.task = curctx->tinfo.task; irqctx->tinfo.previous_esp = current_stack_pointer; irqctx->tinfo.preempt_count = (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); asm volatile( " xchgl %%ebx,%%esp \n" " call *%%edi \n" " movl %%ebx,%%esp \n" : "=a" (arg1), "=d" (arg2), "=b" (ebx) : "0" (irq), "1" (desc), "2" (isp), "D" (desc->handle_irq) : "memory", "cc" ); } else #endif desc->handle_irq(irq, desc); irq_exit(); set_irq_regs(old_regs); return 1; }
|
handle_edge_irq()
do_IRQ() --> handle_edge_irq()
void fastcall handle_edge_irq(unsigned int irq, struct irq_desc *desc) { const unsigned int cpu = smp_processor_id(); spin_lock(&desc->lock); desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) || !desc->action)) { desc->status |= (IRQ_PENDING | IRQ_MASKED); mask_ack_irq(desc, irq); goto out_unlock; } kstat_cpu(cpu).irqs[irq]++; desc->chip->ack(irq); desc->status |= IRQ_INPROGRESS; do { struct irqaction *action = desc->action; irqreturn_t action_ret; if (unlikely(!action)) { desc->chip->mask(irq); goto out_unlock; } if (unlikely((desc->status & (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_MASKED))) { desc->chip->unmask(irq); desc->status &= ~IRQ_MASKED; } desc->status &= ~IRQ_PENDING; spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq, action); if (!noirqdebug) note_interrupt(irq, desc, action_ret); spin_lock(&desc->lock);
} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING); desc->status &= ~IRQ_INPROGRESS; out_unlock: spin_unlock(&desc->lock); }
|
handle_IRQ_event()
handle_edge_irq() --> handle_IRQ_event()
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) { irqreturn_t ret, retval = IRQ_NONE; unsigned int status = 0; handle_dynamic_tick(action); if (!(action->flags & IRQF_DISABLED)) local_irq_enable_in_hardirq(); do { ret = action->handler(irq, action->dev_id); if (ret == IRQ_HANDLED) status |= action->flags; retval |= ret; action = action->next; } while (action); if (status & IRQF_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return retval; }
注: (1) 内核接收到一个中断后,它将依次调用在该中断线上注册的每一个处理程序。因此,一个处理程序知道它是否应该为这个中断负责。如果与它相关的设备并没有产生中断,那么处理程序应该立即退出。这需要硬件设备提供状态寄存器,以便中断处理程序进行检查。毫无疑问,大多数硬件都提供这种功能。
(2) USB设备的中断处理action->handler是usb_hcd_irq() USB主控制器提供了中断状态寄存器regs->intrstatus来保存中断发生的具体情况,这个32位的中断状态寄存器便是用来供中断处理程序判断中断是否由USB设备触发。
| |
阅读(477) | 评论(0) | 转发(0) |