中断子系统5_电流层处理

来源:互联网 发布:sql高阶 编辑:程序博客网 时间:2024/05/15 15:11
    //  电流类型://    1.电平型:handle_level_irq/* *    Level type interrupts are active as long as the hardware line has *    the active level. This may require to mask the interrupt and unmask *    it after the associated handler has acknowledged the device, so the *    interrupt line is back to inactive. *///      译:当中断线电平达到激活电平,中断一直会被激活。 所以需要刚进中断处理函数就要屏蔽掉中断,//          等handler 处理完后再打开中断(unmask)。//      问:为什么要先屏蔽中断中断,后确认呢(mask_and_ack)?//      答:因为cpu周期性采样中断线,当发现电平有效时,触发中断,因此外部设备为了保证cpu可以检测到//          有效电平,需要将电平保持一段时间。当cpu检测到有效电平后,cpu引脚被置位,如果不先屏蔽中断,//          直接确认,当cpu引脚复位时,如果此时电平依然有效,那么同一个中断又被触发,此为不正确的。//            (注:cpu确认是用于复位cpu引脚,对外设的应答在注册的irq_action由特定的驱动程序进行)//      问:这对于编写ISR有什么启示呢?//      答:由于在handle_level_irq调用ISR过程中,中断被屏蔽,因此在此期间的新发生的中断可能会丢失(//          因为电平型中断信号不被中断控制器锁存,电平恢复之前,如果cpu没有通过采样发现此有效电平,//          则中断丢失),所以ISR应该尽快执行完毕。//          //    2.边沿型:handle_edge_irq/* *    Interrupt occures on the falling and/or rising edge of a hardware *    signal. The occurence is latched into the irq controller hardware *    and must be acked in order to be reenabled. After the ack another *    interrupt can happen on the same source even before the first one *    is handled by the assosiacted event handler. If this happens it *    might be necessary to disable (mask) the interrupt depending on the *    controller hardware. This requires to reenable the interrupt inside *    of the loop which handles the interrupts which have arrived while *    the handler was running. If all pending interrupts are handled, the *    loop is left. */ //   译:中断发生在上升沿/下降沿,它会被中断控制器锁存起来,需要ack后才能重新使能。  //   ack后新的中断可以在前一个中断正在被处理时产生,如果这种情况发生,则需要屏蔽中断。 //   同时,需要用一个loop来处理中断处理过程中又有中断产生的情况,在这个loop中重新把 //   中断屏蔽打开。 如果所有pending的在这个loop中重新把中断屏蔽打开。 如果所有pending //   的中断都处理完了,loop就可以离开。 //   问:为什么不需要先屏蔽中断,而是直接确认呢(ack)? //   答:因为边沿型中断在电平的变化沿才有效,所以外设为触发中断,会在中断线上放一个边沿脉冲 //       ,一个边沿脉冲只能触发一次中断,所以不需要防止像电平型中断,同一个中断请求的高电平 //       触发多次中断而需先屏蔽中断的情况。//  在2.6.x版本后,中断描述符irq_desc->handle_irq封装对不同电流类型的处理。//      struct irq_desc//      {//          irq_flow_handler_t handle_irq;//          ...//      }//  电流处理入口://      系统中所有中断统一经过do_IRQ处理://          1.irq_desc提供电流处理例程(irq_desc->handle_irq != NULL),则调用;//          2.否则,通过__do_IRQ处理所有电流类型。//      do_IRQ(regs)//      {   //          ....//          if(irq_desc->handle_irq)//          {//              irq_desc->handle_irq(irq, irq_desc);//          }else//          {//              __do_IRQ(irq, regs);//          }//          ....//      }////  设置irq_desc的电流处理例程//      参数://          typedef void (*irq_flow_handler_t)(unsigned int irq, struct irq_desc *desc);1.1 static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handler){    struct irq_desc *desc;    desc = irq_to_desc(irq);    desc->handle_irq = handler;}//  边沿型中断处理//  函数主要任务://      1.检查中断是否被禁用,或者中断处理函数是否在运行过程中//          1.1 如果是,向芯片屏蔽并确认此中断,设置标志表示有待处理的中断,退出//      2.向芯片确认此次中断//      3.设置中断处理函数在运行中标志//      4.运行中断处理函数//      5.检查在运行中断处理函数过程中,是否有新中断(步骤1中会被设置)//          5.1 如果有,清除标志,转去步骤4//      6.清除中断处理函数在运行中标志,表示所有已经发生的中断都被处理完毕//      7.退出 2.1 void 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);        //如果IRQ_INPROGRESS已经置位,表明另一个CPU正在处理该irq的上一次请求,        //这种情况下,只是简单地设置IRQ_PENDING标志,然后mask_ack_irq后退出,        //中断请求交由原来的CPU继续处理。        if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||                    !desc->action)) {                desc->status |= (IRQ_PENDING | IRQ_MASKED);                mask_ack_irq(desc, irq);                goto out_unlock;        }        //向芯片确认此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;                }                 //处理中断期间,另一次请求可能由另一个cpu响应后挂起,所以在处理完本次请求后还要判断IRQ_PENDING标志,                //如果被置位,当前cpu要接着处理被另一个cpu“委托”的请求。内核在这里设置了一个循环来处理这种情况,                //直到IRQ_PENDING标志无效为止,而且因为另一个cpu在响应并挂起irq时,会mask irq,                //所以在循环中要再次unmask irq,以便另一个cpu可以再次响应并挂起irq。                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);                spin_lock(&desc->lock);         } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);        //中断全部被处理        desc->status &= ~IRQ_INPROGRESS; out_unlock:        spin_unlock(&desc->lock);}//  函数主要任务://      1.向芯片屏蔽并确认此IRQ//      2.如果同一个中断正在被处理,则直接退出//      3.否则,运行设置IRQ_INPROGRESS标志,执行ISR//          3.1.取消IRQ_INPROGRESS标志,解除IRQ屏蔽//      4.退出2.2 void handle_level_irq(unsigned int irq, struct irq_desc *desc){        raw_spin_lock(&desc->lock);        //确认并屏蔽此中断        mask_ack_irq(desc);        //同一个中断正在被处理,则直接退出        if (unlikely(desc->status & IRQ_INPROGRESS))            goto out_unlock;        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);                //没有中断处理函数,或者中断被禁止,退出        if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data)))                goto out_unlock;        desc->status &= ~IRQ_INPROGRESS;        raw_spin_unlock(&desc->lock);        //调用中断处理函数        handle_irq_event(desc);        raw_spin_lock(&desc->lock);        desc->status &= ~IRQ_INPROGRESS;        //解除屏蔽        cond_unmask_irq(desc);out_unlock:        raw_spin_unlock(&desc->lock);}//  参考://      http://en.wikipedia.org/wiki/Interrupt//      http://blog.csdn.net/xiaoxiaomuyu2010/article/details/12162599//      http://blog.csdn.net/droidphone/article/details/7489756//  执行驱动注册的中断处理例程//  函数调用路径://      __do_IRQ->handle_IRQ_event//      handle_level_irq->handle_IRQ_event//      handle_edge_irq->handle_IRQ_event//  函数主要任务://      1.遍历驱动注册的中断处理例程//      2.关中断3.1 fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,                struct irqaction *action){    int ret, retval = 0, status = 0;    //遍历所有已注册的irqaction    do {        //调用驱动注册的处理程序        ret = action->handler(irq, action->dev_id, regs);        if (ret == IRQ_HANDLED)            status |= action->flags;        retval |= ret;        action = action->next;    } while (action);    //中断处理完毕,在中断返回路径上先关中断,iret会恢复eflags(恢复中断标志)    local_irq_disable();    return retval;}//  关于handle_IRQ_event末尾关中断的思考://      do_IRQ->...->handle_IRQ_event,关中断->ret_from_intr//      do_IRQ->...->handle_IRQ_event,关中断->do_softirq 保存中断状态,关中断->...->do_softirq 恢复中断状态->ret_from_intr//      在中断处理过程中防止丢失中断,因此开中断,允许中断嵌套;//      在中断处理结束时,关中断,避免没必要的中断嵌套//      当iret中断返回时,会自动恢复中断状态(eflags)。//  参考://      http://www.unixresources.net/linux/clf/linuxK/archive/00/00/58/82/588249.html//      http://blog.csdn.net/normalnotebook/article/details/1649770