Linux内核-中断机制个人理解
 2016.04.20    |      Linux MMC子系统    |     AilsonJack    |     暂无评论    |     1687 views
By: Ailson Jack
Date: 2016-04-08
个人博客: http://www.only2fire.com/
<p style="text-indent: 2em;">对于Linux的中断,个人理解首先明白三个结构体irq_desc、irq_chip、irqaction之间的关系,把这三个结构体之间的关系搞明白之后,想要弄明白中断从触发,到最后执行中断服务程序就会比较容易,至少在内核中跟踪代码会容易些。<br/></p><p style="text-indent: 2em;">每个中断线都有它自己的irq_desc描述符,所有这些描述符组织在一起就形成了中断描述符数组。</p><p class="artical_littlestyle1">1、一条中断线的中断描述结构体</p><p style="text-indent: 2em;">中断描述符数组存放着各个中断线的中断描述符结构体。</p><p style="text-indent: 0em;"><span style="color: rgb(0, 112, 192);">struct irq_desc {<br/>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255, 0, 0);">unsigned int&nbsp;&nbsp;&nbsp;&nbsp; irq;//这个中断线的中断号</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;struct timer_rand_state *timer_rand_state;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp;&nbsp;&nbsp; *kstat_irqs;<br/><br/>#ifdef CONFIG_INTR_REMAP<br/>&nbsp;&nbsp;&nbsp;&nbsp;struct irq_2_iommu&nbsp; *irq_2_iommu;<br/>#endif<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;irq_flow_handler_t&nbsp; handle_irq;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255, 0, 0);">struct irq_chip &nbsp;&nbsp; *chip; //这个中断线使用的中断控制器</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;struct msi_desc&nbsp; &nbsp; *msi_desc;<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *handler_data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *chip_data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255, 0, 0);">struct irqaction&nbsp;&nbsp; *action; /* IRQ action list *///该中断线的中断服务程序</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp;&nbsp;&nbsp; status; /* IRQ status */<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp;&nbsp;&nbsp; depth; /* nested irq disables */<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp;&nbsp;&nbsp; wake_depth; /* nested wake enables */<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp;&nbsp;&nbsp; irq_count; /* For detecting broken IRQs */<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned long&nbsp;&nbsp; &nbsp; last_unhandled; /* Aging timer for unhandled count */<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp;&nbsp;&nbsp; irqs_unhandled;<br/>&nbsp;&nbsp;&nbsp;&nbsp;raw_spinlock_t&nbsp;&nbsp;&nbsp; lock;<br/><br/>#ifdef CONFIG_SMP<br/>&nbsp;&nbsp;&nbsp;&nbsp;cpumask_var_t&nbsp; affinity;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int &nbsp; node;<br/>#ifdef CONFIG_GENERIC_PENDING_IRQ<br/>&nbsp;&nbsp;&nbsp;&nbsp;cpumask_var_t&nbsp; pending_mask;<br/>#endif<br/>#endif<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;atomic_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; threads_active;<br/>&nbsp;&nbsp;&nbsp;&nbsp;wait_queue_head_t&nbsp;&nbsp;&nbsp; wait_for_threads;<br/><br/>#ifdef CONFIG_PROC_FS<br/>&nbsp;&nbsp;&nbsp;&nbsp;struct proc_dir_entry&nbsp; *dir;<br/>#endif<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;const char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; *name;<br/>} ____cacheline_internodealigned_in_smp;</span></p><p class="artical_littlestyle2">2、描述中断控制器的结构体</p><p style="text-indent: 2em;">这是描述中断控制器的结构体,将其封装成结构体便于管理各个不同类型的中断控制器,比如8259A和APIC。</p><p style="text-indent: 0em;"><span style="color: rgb(0, 112, 192);">struct irq_chip {<br/>&nbsp;&nbsp;&nbsp;&nbsp;const char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *name;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int&nbsp;&nbsp; (*startup)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*shutdown)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*enable)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*disable)(unsigned int irq);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*ack)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*mask)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*mask_ack)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*unmask)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*eoi)(unsigned int irq);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*end)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*set_affinity)(unsigned int irq,<br/>&nbsp;&nbsp;&nbsp;&nbsp;const struct cpumask *dest);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*retrigger)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*set_type)(unsigned int irq, unsigned int flow_type);<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*set_wake)(unsigned int irq, unsigned int on);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*bus_lock)(unsigned int irq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*bus_sync_unlock)(unsigned int irq);<br/><br/>/* Currently used only by UML, might disappear one day.*/<br/>#ifdef CONFIG_IRQ_RELEASE_METHOD<br/>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*release)(unsigned int irq, void *dev_id);<br/>#endif<br/><br/>/*<br/>&nbsp;* For compatibility, -&gt;typename is copied into -&gt;name.<br/>&nbsp;* Will disappear.<br/>*/<br/>&nbsp;&nbsp;&nbsp;&nbsp;const char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *typename;<br/>};<br/></span></p><p class="artical_littlestyle3">3、中断线上的中断服务程序</p><p style="text-indent: 2em;">这是中断线上的中断服务程序结构体。如果该中断线可以被共享,那么将由这个结构体组成一个中断服务程序的链表,如果这条线上有中断产生,那么Linux内核会在handle_IRQ_event()函数中,对该中断线上的每一个注册的中断程序进行执行,这就要求相关设备的中断服务程序应该知道是否它应该对这个中断负责,如果该中断与当前的设备无关,那么处理程序应该立刻退出。</p><p style="text-indent: 0em;"><span style="color: rgb(0, 112, 192);">struct irqaction {<br/>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255, 0, 0);">irq_handler_t handler;//中断服务程序<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned long flags;//IRQF_SHARED表明该中断线可以被共享</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;const char *name;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255, 0, 0);">void *dev_id;//在共享中断中,该值的唯一性将当前的中断服务程序与其他服务程序区分<br/>&nbsp;&nbsp;&nbsp;&nbsp;struct irqaction *next;//指向下一个中断服务程序<br/>&nbsp;&nbsp;&nbsp;&nbsp;int irq;//分配到指定中断号的中断描述结构体中</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;struct proc_dir_entry *dir;<br/>&nbsp;&nbsp;&nbsp;&nbsp;irq_handler_t thread_fn;<br/>&nbsp;&nbsp;&nbsp;&nbsp;struct task_struct *thread;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned long thread_flags;<br/>};</span><br/></p><p class="artical_littlestyle4">4、中断处理程序</p><p style="text-indent: 2em;">中断处理程序注册函数:<br/><span style="color: rgb(0, 112, 192);">request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,<br/>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; const char *name, void *dev)</span><br/></p><p style="text-indent: 2em;">中断处理程序释放函数:<br/><span style="color: rgb(0, 112, 192);">void free_irq(unsigned int irq, void *dev_id)</span><br/></p><p style="text-indent: 2em;">中断从硬件到内核的路由:<br/></p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.26/1535260614147770.png" onclick="preview_image(&#39;/uploads/AilsonJack/2018.08.26/1535260614147770.png&#39;)"/></p><p style="text-indent: 2em;">下面是自己总结的一幅中断线描述数组的图:</p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.26/1535260616788684.png" onclick="preview_image(&#39;/uploads/AilsonJack/2018.08.26/1535260616788684.png&#39;)"/></p><p class="artical_littlestyle1">5、中断的下半部</p><p style="text-indent: 2em;">Linux的中断工作在中断上下文,因此不能够被工作于进程上下文的任务打断,如果中断服务程序处理的工作比较多,就会严重影响到用户层的任务,为了解决这个问题,Linux将中断的处理分为上半部与下半部。其中的上半部就是上面提到的中断服务程序,它用于需要马上进行处理的任务。对于那些与中断相关,但是不要求马上进行处理的任务,就可以将其放在中断的下半部进行处理。<br/></p><p style="text-indent: 2em;">中断的下半部的实现机制主要包括:软中断,tasklet,工作队列。其中软中断和tasklet工作在中断上下文,而工作队列工作在进程上下文。<br/></p><p style="text-indent: 2em;">对于工作在中断上下文的中断处理程序,软中断,tasklet不能够休眠,即不能够使用信号量或者其他阻塞式的函数。<br/></p>
欢迎关注博主的公众号呀,精彩内容随时掌握:
热情邀请仔细浏览下博客中的广告,万一有对自己有用或感兴趣的呢。◕ᴗ◕。。
如果这篇文章对你有帮助,记得点赞和关注博主就行了^_^,当然了能够赞赏博主,那就非常感谢啦!
注: 转载请注明出处,谢谢!^_^
转载请注明来源: 本文链接:  By: AilsonJack
Linux内核-中断机制个人理解  |  说好一起走
暂无评论,要不要来个沙发
发表评论

 
Copyright © 2015~2023  说好一起走   保留所有权利   |  百度统计  蜀ICP备15004292号