Linux中断处理流程
来源:行业资讯 /
时间: 2024-12-13
Chip-Level hardware Encapsulation:硬件设备层,mask、ack等中断系统硬件寄存器的操作,对应到图中的irq_chip。
<p><img src="https://img.xpwin7.com/2021/1015/202134151134562.jpg" ,="" alt="Linux中断处理流程"/></p><br/>
<div>
2)irq_desc:是一个全局数组,每个中断源对应一个descriptor。</div>
<div>
3)handle_irq:它为每个不同类型中断源的处理函数入口,调用路径为:asm_do_IRQ->handle_irq->generic_handle_irq->generic_handle_irq_desc-> handle_irq。不同类型中断源使用不同的处理方式,在该中断子系统初始化时使用函数irq_set_handler进行设置或直接给函数指针赋值。</div>
<div>
irq_chip:它替代了老版本hw_interrupt_type,该结构体内的函数集为对应中断源硬件操作的mask、unmask、应答ack、mask_ack等,在该中断子系统初始化时使用函数irq_set_chip进行设置。</div>
<div>
handle_level_irq处理电平信号触发的中断源类型,该函数会调用chip的irq_mask、irq_ack来mask并ack(告诉中断控制器,已经有人响应该中断了,可以继续产生下一个新中断了)这个中断信号源,否则该中断会被重复处理;</div>
<div>
handle_egde_irq处理边沿信号触发的中断源类型,只ack就可以,不需要mask,下一个新的该类型中断可以pending到SRCPEND寄存器。</div>
<div>
</div>
<div>
对于多核 CPU,如果其他核正在处理该中断,可以通过函数irqd_irq_inprogress检测 irq_desc ->irq_data->state_use_accessors状态是否为IRQD_IRQ_INPROGRESS来识别。</div>
<div>
handle_irq(=handle_level_irq or handle_egde_irq or ...)会通过handle_irq_event->handle_irq_event_percpu(2.6版本为handle_IRQ_event)调用真正的设备中断处理函数action->handler。</div>
<div>
4)irqaction:它对应具体设备的中断描述,handler为具体isr中断服务函数,dev_id用来区别共享中断中的不同设备,next指针指向同一个中断源(共享中断)下一个设备的irqaction,当中断发生,共享中断的设备isr都将被调用,因此各个设备的isr内要有能力判断该中断是不是本设备发出的。关于共享中断《Linux设备驱动》的一段话:“无论何时 2 个或多个驱动在共享中断线, 并且硬件中断在这条线上中断处理器, 内核为这个中断调用每个注册的处理者, 传递它的 dev_id 给每个. 因此, 一个共享的处理者必须能够识别它自己的中断并且应当快速退出当它自己的设备没有被中断时.”我认为这个说法是错误的,首先中断信号只是io上的一个电信号,不可能传递dev_id信息给cpu,那么内核也不知道是哪个设备发出的中断信号;再者如果真的有了已知的dev_id,也就不需要调用所有的共享中断的isr了。</div>
<div>
因此,要每个设备的isr来判断该中断是不是自己发出的,需要硬件支持,比如通过简单的check一个设备的标志寄存器来完成,不是本设备的,立刻退出中断。</div>
<div>
另外,在处理共享中断时不能单独在某个设备内进行disable、enable irq的动作,这样会影响其他共享中断的设备。</div>
<div>
三、中断的软件处理流程<br/>
<p><img src="https://img.xpwin7.com/2021/1015/202134151134563.jpg" ,="" alt="Linux中断处理流程"/></p></div>