博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
中断子系统5_电流层处理
阅读量:7010 次
发布时间:2019-06-28

本文共 5172 字,大约阅读时间需要 17 分钟。

//  中断电流类型://      边沿型(edge);//          通过电位变化触发中断(上升沿/下降沿),如果外设希望触发一个中断,它在irq line上发送一个脉冲,//          然后释放irq line恢复到inactive状态。cpu通过检测irq line上的脉冲来触发中断处理函数的执行。//      电平型(level)://          通过特定电位触发中断,如果外设希望触发一个中断,它会将irq line设置到active level(高电平/低电平),//          然后一直保持此irq line为active level,直到中断被处理。cpu通过周期性采样irq line的电平来触发中断处理函数的执行。//	在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标志没有被设置的情况下,只是ack irq,并没有mask irq,以便复位设备的中断请求引脚,        //在这之后的中断处理期间,另外的cpu可以再次响应同一个irq请求,如果IRQ_INPROGRESS已经置位,        //表明另一个CPU正在处理该irq的上一次请求,这种情况下,他只是简单地设置IRQ_PENDING标志,然后mask_ack_irq后退出,        //中断请求交由原来的CPU继续处理。因为是mask_ack_irq,所以系统实际上只允许挂起一次中断。        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);}//  电平型中断//      只要设备的中断请求引脚(中断线)保持在预设的触发电平,中断就会一直被请求,//        所以,为了避免同一中断被重复响应,必须在处理中断前先把mask irq,然后ack irq,//      以便复位设备的中断请求引脚,响应完成后再unmask irq。//  函数主要任务://      1.向芯片屏蔽并确认此中断//      2.运行中断处理函数//      3.解除屏蔽//      4.退出2.2 void handle_level_irq(unsigned int irq, struct irq_desc *desc){        raw_spin_lock(&desc->lock);        //确认并屏蔽此中断        mask_ack_irq(desc);        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);                //没有中断处理函数,或者中断被禁止,退出        if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data)))                goto out_unlock;        //调用中断处理函数        handle_irq_event(desc);        //解除屏蔽        cond_unmask_irq(desc);out_unlock:        raw_spin_unlock(&desc->lock);}//  虽然handle_level_irq对电平中断的流控进行了必要的处理,因为电平中断的特性:只要没有ack irq,中断线会一直有效,//  所以我们不会错过某次中断请求,但是驱动程序的开发人员如果对该过程理解不透彻,特别容易发生某次中断被多次处理的情况。//  特别是使用了中断线程(action->thread_fn)来响应中断的时候:通常mask_ack_irq只会清除中断控制器的pending状态,//  很多慢速设备(例如通过i2c或spi控制的设备)需要在中断线程中清除中断线的pending状态,但是未等到中断线程被调度执行的时候,//  handle_level_irq早就返回了,这时已经执行过unmask_irq,设备的中断线pending处于有效状态,中断控制器会再次发出中断请求,//  结果是设备的一次中断请求,产生了两次中断响应。要避免这种情况,最好的办法就是不要单独使用中断线程处理中断,//  而是要实现request_threaded_irq()的第二个参数irq_handler_t:handler,在handle回调中使用disable_irq()//  关闭该irq,然后在退出中断线程回调前再enable_irq()。//  参考://      http://en.wikipedia.org/wiki/Interrupt//      http://blog.csdn.net/xiaoxiaomuyu2010/article/details/12162599//      http://blog.csdn.net/droidphone/article/details/7489756

你可能感兴趣的文章
linux下的静态库和动态库分析
查看>>
zabbix自动报警邮件正文变成附件问题解决
查看>>
豆瓣阿北:用户价值大于产品体验,通过产品做运营
查看>>
我的友情链接
查看>>
利用clonezilla克隆、还原CentOS整个系统
查看>>
解决127.0.0.1 localhost 劫持问题
查看>>
winscp连接虚拟机Linux被拒绝的问题解决方案
查看>>
教程-Delphi设置功能表
查看>>
Java中的多线程,线程池
查看>>
软件下载站
查看>>
Zend Studio 12 生成 WSDL
查看>>
JAVA学习心得
查看>>
【夯实Mysql基础】记一次mysql语句的优化过程
查看>>
VBPR: Visual Bayesian Personalized Ranking from Implicit Feedback-AAAI2016 -20160422
查看>>
servlet injection analysis
查看>>
(原)centos7安装和使用greenplum4.3.12(详细版)
查看>>
Hive之 hive与hadoop的联系
查看>>
java中的==、equals()、hashCode()源码分析
查看>>
HDU 3613 Best Reward 正反两次扩展KMP
查看>>
zepto.js 源码解析
查看>>