edge中断分析

眼下正在调试msix中断,在測试过程中发现会概率性的丢失中断。Msix中断默认是edge触发的中断,edge触发的中断是在中断相应pin发生电平信号跳变的时候,会发出一个中断请求。

由于跳变是一瞬间的。不会像level触发中断那样一直保持电平不变,这样就可能会漏掉某一个跳变的瞬间,表现就是丢失了一个中断。

内核中处理edge触发中断的函数为handle_edge_irq,此函数有do_IRQ函数调用而来。

void handle_edge_irq(unsigned int irqstruct irq_desc *desc 

  

  raw_spin_lock(&desc->lock);  

           /*由于接收到中断,所以清除以下两个标志*/

  desc->istate &= ~(IRQS_REPLAY IRQS_WAITING);    

          /*IRQ是否被禁止,或者正在处理中。或者没有挂接中断处理函数*/

  if (unlikely(irqd_irq_disabled(&desc->irq_data||  

        irqd_irq_inprogress(&desc->irq_data|| !desc->action))  

   if (!irq_check_poll(desc))  

    desc->istate |= IRQS_PENDING /*设置irq处于挂起状态*/ 

    mask_ack_irq(desc);  /*向硬件发ACK,屏蔽中断*/

    goto  out_unlock 

    

   

  kstat_incr_irqs_this_cpu(irqdesc); /*process/interrupts中相应irq计算加1*/

         /*cpu对此IRQ的回应,表示准备接收此IRQ的下一个中断*/

 desc->irq_data.chip->irq_ack(&desc->irq_data);  

 

 do  

  if (unlikely(!desc->action)) { /*没有挂接中断处理函数*/

   mask_irq(desc);    /*屏蔽IRQ*/

   goto  out_unlock 

   

 /*IRQ处于中断挂起状态*/  

  if (unlikely(desc->istate & IRQS_PENDING)) {  

   if (!irqd_irq_disabled(&desc->irq_data&&  

       irqd_irq_masked(&desc->irq_data))  

    unmask_irq(desc);

   

                  /*处理中断*/

  handle_irq_event(desc);    

 

 }  while ((desc->istate & IRQS_PENDING&&    /*有挂起的中断须要处理*/

   !irqd_irq_disabled(&desc->irq_data));   /*irq没有禁止*/

istate成员刚開始在irq_desc结构体中没找到,事实上它的定义例如以下

#define istate core_internal_state__do_not_mess_with_it

istate相应的是core_internal_state__do_not_mess_with_it成员。

IRQS_REPLAY标志是用来拯救丢失的中断。此标志在check_irq_resend函数中设置通过中断控制器APIC上的中断信号又一次向cpu发中断。而不是通过外设硬件来重发中断。这里进入到了handle_edge_irq函数表示已经收到了中断。不须要重发,所以清除此标志。

IRQS_WAITING标志表示中断的到来,这里收到了中断,因此也清除此标志。

此标志在handle_xxx_irq函数的開始都会清除掉。

假设<1>当前irq被禁止<2>当前irq正在处理中<3>当前irq没有挂接处理函数。则我们不处理接收到的此IRQ。假设满足上面的条件,我们就设置此IRQIRQS_PENDING挂起状态,并屏蔽中断,然后返回。放弃中断的处理过程,留给正在处理此IRQ中断的cpu来处理此次pending的中断。

irq_ack函数的底层实现是写eoi寄存器。是cpu对此IRQ的回应,表示irq希望清除此IRQpending状态(用于清除APIC IRRpending位),准备接收下一个中断。这样其它的cpu就能够接收此IRQ进行处理了。

程序接下来是一个while循环,循环的条件是IRQ没有被禁止而且有pending的待处理的中断

由于在处理中断的过程中,由于ack了。可能其它的cpu又接收到了此IRQ新的中断。

假设此IRQ没有挂接中断处理函数,就直接屏蔽此IRQ,返回。

假设irq处于IRQS_PENDING状态。中断没有被禁止可是被屏蔽的情况下。调用unmask_irq取消屏蔽。想想为什么会处于IRQS_PENDING状态。并这样处理?前面讲到当此IRQ正在处理中,新接收到的中断,就会设置IRQS_PENDING状态。并屏蔽此IRQ

Edge触发方式的中断easy丢中断,因此在处理中断时候不能长时间的屏蔽IRQ

在handle_edge_irq函数一上来就推断在irq没用被禁止,没用正在处理的情况下,仅仅是ack回应了硬件。没用屏蔽irq,表示另外的cpu能够接收此IRQ的中断。

原文地址:https://www.cnblogs.com/yfceshi/p/7298568.html