Linux内核-中断机制个人理解
<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/> <span style="color: rgb(255, 0, 0);">unsigned int irq;//这个中断线的中断号</span><br/> struct timer_rand_state *timer_rand_state;<br/> unsigned int *kstat_irqs;<br/><br/>#ifdef CONFIG_INTR_REMAP<br/> struct irq_2_iommu *irq_2_iommu;<br/>#endif<br/><br/> irq_flow_handler_t handle_irq;<br/> <span style="color: rgb(255, 0, 0);">struct irq_chip *chip; //这个中断线使用的中断控制器</span><br/> struct msi_desc *msi_desc;<br/> void *handler_data;<br/> void *chip_data;<br/> <span style="color: rgb(255, 0, 0);">struct irqaction *action; /* IRQ action list *///该中断线的中断服务程序</span><br/> unsigned int status; /* IRQ status */<br/><br/> unsigned int depth; /* nested irq disables */<br/> unsigned int wake_depth; /* nested wake enables */<br/> unsigned int irq_count; /* For detecting broken IRQs */<br/> unsigned long last_unhandled; /* Aging timer for unhandled count */<br/> unsigned int irqs_unhandled;<br/> raw_spinlock_t lock;<br/><br/>#ifdef CONFIG_SMP<br/> cpumask_var_t affinity;<br/> unsigned int node;<br/>#ifdef CONFIG_GENERIC_PENDING_IRQ<br/> cpumask_var_t pending_mask;<br/>#endif<br/>#endif<br/><br/> atomic_t threads_active;<br/> wait_queue_head_t wait_for_threads;<br/><br/>#ifdef CONFIG_PROC_FS<br/> struct proc_dir_entry *dir;<br/>#endif<br/><br/> const char *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/> const char *name;<br/> unsigned int (*startup)(unsigned int irq);<br/> void (*shutdown)(unsigned int irq);<br/> void (*enable)(unsigned int irq);<br/> void (*disable)(unsigned int irq);<br/><br/> void (*ack)(unsigned int irq);<br/> void (*mask)(unsigned int irq);<br/> void (*mask_ack)(unsigned int irq);<br/> void (*unmask)(unsigned int irq);<br/> void (*eoi)(unsigned int irq);<br/><br/> void (*end)(unsigned int irq);<br/> int (*set_affinity)(unsigned int irq,<br/> const struct cpumask *dest);<br/><br/> int (*retrigger)(unsigned int irq);<br/> int (*set_type)(unsigned int irq, unsigned int flow_type);<br/> int (*set_wake)(unsigned int irq, unsigned int on);<br/><br/> void (*bus_lock)(unsigned int irq);<br/> void (*bus_sync_unlock)(unsigned int irq);<br/><br/>/* Currently used only by UML, might disappear one day.*/<br/>#ifdef CONFIG_IRQ_RELEASE_METHOD<br/> void (*release)(unsigned int irq, void *dev_id);<br/>#endif<br/><br/>/*<br/> * For compatibility, ->typename is copied into ->name.<br/> * Will disappear.<br/>*/<br/> const char *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/> <span style="color: rgb(255, 0, 0);">irq_handler_t handler;//中断服务程序<br/> unsigned long flags;//IRQF_SHARED表明该中断线可以被共享</span><br/> const char *name;<br/> <span style="color: rgb(255, 0, 0);">void *dev_id;//在共享中断中,该值的唯一性将当前的中断服务程序与其他服务程序区分<br/> struct irqaction *next;//指向下一个中断服务程序<br/> int irq;//分配到指定中断号的中断描述结构体中</span><br/> struct proc_dir_entry *dir;<br/> irq_handler_t thread_fn;<br/> struct task_struct *thread;<br/> 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/> 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('/uploads/AilsonJack/2018.08.26/1535260614147770.png')"/></p><p style="text-indent: 2em;">下面是自己总结的一幅中断线描述数组的图:</p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.26/1535260616788684.png" onclick="preview_image('/uploads/AilsonJack/2018.08.26/1535260616788684.png')"/></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>
你可能也喜欢:
暂无评论,要不要来个沙发
发表评论
JLink V9掉固件修复(灯不亮) 3Zephyr笔记2 - 在STM32F429上运行HelloWorld 2计算NandFlash要传入的行地址和列地址 1Linux MMC子系统 - 6.eMMC 5.1工作模式-设备识别模式 0Linux MMC子系统 - 5.eMMC 5.1工作模式-引导模式 0Linux MMC子系统 - 4.eMMC 5.1常用命令说明(2) 0
标签云
Linux嵌入式实用技巧ARM内核学习问题集合CC++编程语言阅读笔记汇编Linux内核完全注释Windows驱动开发计算机基础ARM11ARMv7-ASTM32IDESublimeLinux内核学习eMMCMMC子系统Ubuntu操作系统OfficeVMWareAPUEgccRTOS中断漫游世界随笔感悟开发工具软件应用编程VsCodearmccarmclang编译器ZephyrSPIJLink网卡驱动安装各种芯片库函数NFSμCOS内核sambaFlashUnix命令与脚本输入法Linux内核设计与实现gitRIFFWAVJATGFTPar8161安装centos有线上网μCGUI字库工程建立右键菜单网络文件系统Firefox百度NTFS文件系统CodeBlocksCentOS数据结构算法PhotoShop51KeilQTUltraEditscanfglibc宏定义UIDGID优先级娱乐天地SourceInsight磁盘扇区总线I2CPDFBComparePythonI2SFPUMakefileSWDCPUARP软件推荐FileZilla