Linux中断子系统分析之(一):整体框架
Linux中断子系统分析之(二):通用的中断处理
Linux中断子系统分析之(三):irq domain
Linux中断子系统分析之(四):驱动程序申请中断
中断的硬件框架
处理器一般只有两根左右的中断引脚,而管理的外设却很多。为了解决这个问题,现代设备的中断信号线并不是与处理器直接相连,而是与一个称为中断控制器的设备相连接,后者才跟处理器的中断引脚直接连接。一个中断硬件组成架构的示例,如下图:
中断控制器有的是支持多个CPU,如ARM的GIC、x86的APIC,有的不支持。
在庞大复杂的硬件系统中,外设很多,硬件系统中可能就不止一个中断控制器了,中断控制器可以级联。一个中断级联的硬件框架示例,如下图:
Linux的中断子系统的软件框架图如下所示:
最上面的driver层,是中断的使用者,使用Linux kernel通用中断处理模块的API。
通用中断处理层,是硬件代码无关,抽象了一套数据结构与接口实现irq相关的管理,提供了通用的中断处理函数。
CPU arch相关的中断处理,如异常向量表相关设置、中断上下文的保护与恢复等,和系统使用的具体的CPU arch相关。
中断控制器驱动,实现中断控制器的编程接口,与系统使用的中断控制器相关。
最底层的就是硬件层,包括CPU和中断控制器。
基本概念
IRQ number
在Linux kernel中,使用IRQ number标识一个中断,每个IRQ number在系统中是唯一的。当发送中断时,内核可以根据IRQ number找到对应的中断服务例程。这个IRQ number是一个虚拟的interrupt ID,和硬件无关,仅仅是被CPU用来标识一个中断,也被叫做软件中断号。
HW interrupt ID
对于中断控制器而言,它收集了多个外设的中断并向上传递,因此,中断控制器需要对外设中断进行编号。中断控制器使用HW interrupt ID来标识外设的中断。HW interrupt ID也被叫做硬件中断号。
irq domain
在一个硬件相对简单的系统里,只有一个中断控制器,硬件中断号可以直接作为软件中断号,但在一个有中断控制器级联的系统里,就不能这样这么做了。比如控制器A接有一个外设,对应的硬件中断号为1,而控制器B接有的一外设,对应的硬件中断号同样为1,所以需要将硬件中断号映射为软件中断号。面对越来越复杂的系统,Linux中断子系统提供了相应的映射机制,通过irq domain来解决映射的问题。所谓domain,就是领域,范围的意思,也就是说,任何的定义出了这个范围就没有意义了。每个中断控制器都可以连接若干个外设的中断请求(interrupt source),中断控制器会对连接其上的interrupt source进行编号(硬件中断号),但这个编号仅仅限制在本中断控制器,所以每个中断控制器都相当于一个irq domain,irq domain是由中断控制器驱动创建和负责维护的。
中断流控处理
因为各种中断请求的电气特性会有所不同,又或者中断控制器的特性也不同,这会导致以下这些处理也会有所不同:
- 何时对中断控制器发出ack回应;
- 对于电平中断触发的中断,mask_irq和unmask_irq的处理,
- 有些中断控制器需要eoi回应,有些不用;
这叫做中断的流控处理。
为此,通用中断子系统把几种常用的流控类型进行了抽象,并为它们实现了相应的标准函数。
目前的通用中断子系统实现了以下这些标准流控回调函数:
- handle_simple_irq 用于简易流控处理;
- handle_level_irq 用于电平触发中断的流控处理;
- handle_edge_irq 用于边沿触发中断的流控处理;
- handle_fasteoi_irq 用于需要响应eoi的中断控制器;