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触发方式的中断容易丢中断,因此在处理中断时候不能长时间的屏蔽IRQ。在handle_edge_irq函数一上来就判断在irq没用被禁止,没用正在处理的情况下,只是ack回应了硬件,没用屏蔽irq,表示另外的cpu可以接收此IRQ的中断。

发布了40 篇原创文章 · 获赞 14 · 访问量 9万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览