文章目录
前言
本章我们将讲解下和中断相关的知识,了解内核中断的框架和中断的概念,对于arm的中断控制器(GIC v3)相关内容,主要是借鉴参考手册简单解释下。
一、中断子系统框架
Linux中的中断相似于之前STM32的中断,是硬件在需要时向CPU发出的一种信号,导致CPU暂时停止当前正在执行的程序,转而处理这个硬件请求的一种机制。
中断发生在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而去为该内部或外部事件或预先安排的事件服务,服务完毕后再返回继续执行原来的程序。
1. 中断硬件简单描述
中断硬件主要有三种器件参与,各个外设、中断控制器和CPU。之间的关系可以简单看下下面图片:
2. 中断的软件描述
一个完整的中断子系统框架可以分为四个层次,由上到下分别为用户层、通用层、硬件相关层和硬件层,每个层相关的介绍如下所示:
- 用户层:用户层是中断的使用者,主要包括各类设备驱动。这些驱动程序通过中断相关的接口进行中断的申请和注册。当外设触发中断时,用户层驱动程序会进行相应的回调处理,执行特定的操作。
- 通用层:通用层也可称为框架层,它是硬件无关的层次。通用层的代码在所有硬件平台上都是通用的,不依赖于具体的硬件架构或中断控制器。通用层提供了统一的接口和功能,用于管理和处理中断,使得驱动程序能够在不同的硬件平台上复用。
- 硬件相关层:硬件相关层包含两部分代码。一部分是与特定处理器架构相关的代码,比如ARM64处理器的中断处理相关代码。这些代码负责处理特定架构的中断机制,包括中断向量表、中断处理程序等。另一部分是中断控制器的驱动代码,用于与中断控制器进行通信和配置。这些代码与具体的中断控制器硬件相关。
- 硬件层:硬件层位于最底层,与具体的硬件连接相关。它包括外设与SoC(系统片上芯片)的物理连接部分。中断信号从外设传递到中断控制器,由中断控制器统一管理和路由到处理器。硬件层的设计和实现决定了中断信号的传递方式和硬件的中断处理能力。
二、GIC v3中断控制器
ARM多核处理器里最常用的中断控制器是GIC, GIC是Generic Interrupt Controller的缩写,提供了灵活的和可扩展的中断管理方法,支持单核系统到数百个大型多芯片设计的核心。 主要作用就是接受硬件中断信号,通过一定的设置策略,然后分发给对应的CPU进行处理。
GIC v3中断控制器是ARM公司推出的一款与cortex-A和cortex-R处理器配合使用的中断控制器,广泛应用于基于armv8的SOC设计中。GIC v3为CPU处理所有连接到其上的中断,包括管理所有的中断源、中断行为、中断分组以及中断路由方式等。同时,它还提供相应的寄存器接口用于软件对这些行为的控制。
1. GIC v3基本结构
GIC v3包含了SPI(Shared Peripheral Interrupt)、PPI(Private Peripheral Interrupt)、SGI(Software Generated Interrupt)和LPI(Locality-Specific Peripheral Interrupt)四种中断类型,以及distributor、redistributor、ITS(Interrupt Translation Service)和CPU interface四大组件。
GIC v3中,将cpu interface从GIC中抽离,放入到了cpu中,cpu interface通过AXI Stream,与gic进行通信。 当GIC要发送中断,GIC通过AXI stream接口,给cpu interface发送中断命令,cpu interface收到中断命令后,根据中断线映射配置,决定是通过IRQ还是FIQ管脚,向cpu发送中断。
1.1 Distributor
Distributor是GIC v3中用于管理共享外设中断(SPI)的关键组件。它负责接收来自外设的SPI中断请求,并根据配置决定中断的优先级以及将中断路由到哪个Redistributor。
- 关键特性:
- 中断分发:Distributor根据中断的优先级、亲和性(affinity)等配置,将SPI中断路由到适当的Redistributor。
- 优先级管理:Distributor为每个SPI中断设置优先级,确保高优先级的中断能够优先得到处理。
- 中断状态管理:Distributor维护中断的状态信息,如中断是否激活、是否挂起等。
- 寄存器接口:
- GICD_系列寄存器(如GICD_ISENABLER、GICD_ICENABLER、GICD_IPRIORITYR等)用于配置Distributor的行为,包括启用/禁用中断、设置中断优先级等。
1.2 Redistributor
Redistributor与CPU接口连接,负责将来自Distributor的中断路由到正确的CPU。在多核系统中,Redistributor确保中断被正确地分发到目标CPU或CPU组。
-
关键特性:
- 中断路由:Redistributor根据配置将中断路由到相应的CPU接口。
- 亲和性管理:Redistributor支持中断的亲和性配置,允许中断被路由到特定的CPU或CPU组。
-
寄存器接口:
- GICR_系列寄存器(如GICR_ISENABLER、GICR_ICENABLER等)用于配置Redistributor的行为,包括启用/禁用中断、设置中断路由等。
1.3 ITS
ITS是GIC v3中用于处理基于消息的中断(LPI)的组件。它提供LPI中断的转换服务,将来自虚拟中断源的LPI中断转换为物理中断源,并将其路由到适当的Redistributor。
- 关键特性:
- 中断转换:ITS将LPI中断转换为物理中断,以便在物理世界中进行处理。
- 中断路由:ITS负责将LPI中断路由到正确的Redistributor。
1.4 CPU interface
CPU interface是GIC v3与CPU之间的接口,负责将中断传递到它所连接到的处理器元素(PE,即CPU)。当Redistributor将中断路由到某个CPU接口时,该接口会将中断信号发送到相应的CPU。
- 关键特性:
- 中断传递:CPU interface将来自Redistributor的中断信号传递给CPU。
- 中断状态管理:CPU interface可能还负责维护中断的状态信息,如中断是否已被CPU接收、是否正在处理等。
2. 中断类型与特点
- SPI:共享外设中断,不与特定的CPU绑定,可以根据affinity配置被路由到任意CPU或一组特定的CPU上。
- PPI:私有外设中断,每个处理器私有的中断类型,即一个特定的中断只会被路由到特定的处理器上。
- SGI:软件生成中断,没有实际的物理连线,而是由软件通过写寄存器方式触发,只支持边沿触发。
- LPI:基于消息的中断,LPI相关的配置保存在内存中而非寄存器。
NTID范围 | 中断类型 | 备注 |
---|---|---|
0 - 15 | SGI(软件生成中断) 文本居右 | 每个核心分别存储 |
16 - 31 | PPI(私有外设中断) | 每个核心分别存储 |
32 - 1019 | SPI(共享外设中断) | |
1020 - 1023 | 特殊中断号 | 用于表示特殊情况 |
1024 - 8191 | 保留 | |
8192及更大 | LPI(特定局部外设中断) | 上限由实现定义 |
- Inactive(非活动状态):中断源当前未被触发。
- Pending(等待状态):中断源已被触发,但尚未被处理器核心确认。
- Active(活动状态):中断源已被触发,并且已被处理器核心确认。
- Active and Pending(活动且等待状态):已确认一个中断实例,同时另一个中断实例正在等待处理。
每个外设中断可以是以下两种类型之一:
- 边沿触发(Edge-triggered):
这是一种在检测到中断信号上升沿时触发的中断,然后无论信号状态如何,都保持触发状态,直到满足本规范定义的条件来清除中断。 - 电平触发(Level-sensitive):
这是一种在中断信号电平处于活动状态时触发的中断,并且在电平不处于活动状态时取消触发。
3. 中断号
在linux 内核中,我们使用IRQ number和HW interrupt ID两个ID来标识一个来自外设的中断:
- IRQ number:CPU需要为每一个外设中断编号,我们称之IRQ Number。这个IRQ number是一个虚拟的interrupt ID,和硬件无关,仅仅是被CPU用来标识一个外设中断。
- HW interrupt ID:对于GIC中断控制器而言,它收集了多个外设的interrupt request line并向上传递,因此,GIC中断控制器需要对外设中断进行编码。GIC中断控制器用HW interrupt ID来标识外设的中断。如果只有一个GIC中断控制器,那IRQ number和HW interrupt ID是可以一一对应的,如下图所示:
但如果是在GIC中断控制器级联的情况下,仅仅用HW interrupt ID就不能唯一标识一个外设中断,还需要知道该HW interrupt ID所属的GIC中断控制器(HW interrupt ID在不同的Interrupt controller上是会重复编码的)。
三、函数编写
3.1 相关API函数
函数名 | 描述 |
---|---|
irq_of_parse_and_map( ) | 解析得到软中断号 |
request_irq( ) | 注册中断 |
devm_request_irq( ) | 注册中断,申请的是内核“managed”的资源 |
free_irq( ) | 释放中断 |
*irq_handler_t( ) | 指定一个中断处理函数 |
enable_irq( ) | 中断的使能 |
disable_irq( ) | 中断的屏蔽 |
gpio_to_irq( ) | 将 GPIO 引脚映射到对应中断号的函数 |
//解析得到软中断号
unsigned int irq_of_parse_and_map(struct