✨前言:
PCIe中断通常分为以下几种:
INTx传统中断:
这是遵循早期PCI总线规范的传统中断方式。在PCI总线中,设备使用一个共享的中断线(INTA#, INTB#, INTC# 或 INTD#)向CPU发送中断信号。PCIe中也提供了对这些传统中断的支持,以确保与旧设备的兼容性。但由于这种方式使用的是共享线路,它可能导致中断冲突,并且效率低下。
MSI(Message Signaled Interrupts):
MSI是一种改进的中断机制,它不再依赖共享的物理中断线。相反,设备通过写入特定的数据到特定的内存地址向CPU发送一个中断消息。由于中断不再共享线路,因此可以避免传统中断的一些限制。MSI机制支持单个或者多个中断消息,增加了可扩展性和灵活性。
MSI-X(MSI eXtended):
MSI-X是在MSI基础上的进一步扩展,允许更多的中断向量,优化了中断处理。MSI-X支持为每个设备提供多达2048个独立的中断向量。每个中断都有独立的中断标识和目标地址,这使得CPU可以更有效率地分配和处理中断。
✨一、INTx 机制介绍
一个简单的PCI总线INTx中断实现流程,如下图所示。
📌 流程
1.首先,PCI设备通过INTx边带信号产生中断请求,经过中断控制器(Interrupt Controller,PIC)后,转换为INTR信号,并直接发送至CPU;
2.CPU收到INTR信号置位后,意识到了中断请求的发生,但是此时并不知道是什么中断请求。于是通过一个特殊的指令来查询中断请求信息,该过程一般被称为中断应答(Interrupt
Acknowledge);
3.该特殊指令被发送至PIC后,PIC会返回一个8bits的中断向量(Interrupt Vector)值给CPU。该中断向量值与其发送的INTR请求是对应的;
4.CPU收到来自PIC的中断向量值后,会去其Memory中的中断向量表(Interrupt Table)中查找对应的中断服务程序(Interrupt Service Routines,ISR)在Memory的位置;
5.然后CPU读取ISR程序,进而处理该中断。
上面的例子主要是基于早期的单核CPU设计的,并没有考虑到目前多核CPU的情况。因此,在后续的PCI Spec中,将PIC替换为IO APIC(Advanced Programmed Interrupt Controller)。如下图所示:
实际上,在PCIe总线中,传统的中断机制(INTx)已经很少被使用,很多应用甚至直接将该功能禁止了。无论是在PCI总线(V2.3及以后的版本),还是PCIe总线中,都可以通过配置空间中的配置命令寄存器(Configuration Command Register来禁止INTx中断机制),如下图所示。不过,需要特别注意的是,虽然该bit的名称为中断禁止(Interrupt Disable),但是其只会影响INTx,对MSI/MSI-X不会造成影响。因为MSI/MSI-X的使能(或禁止)是通过配置空间中的MSI/MSI-X Capability Command Register来实现的,并且一旦使能了MSI/MSI-X,PCI总线/PCIe总线便会自动地禁止INTx。
并且可以通过配置状态寄存器的中断状态(Interrupt Status)bit来确定当前的中断状态,如下图所示:
INTx相关的寄存器在配置空间的位置如下图所示,Interrupt Pin和Interrupt Line分别定义了中断边带信号引脚号(INTA#~INTD#)和中断向量号(IRQ0 ~ IRQ255)。
然而,PCIe总线继承了PCI总线的INTx中断机制,但是在实际的PCIe设备之间的中断信息传输中使用的并非边带信号INTx,而是基于消息(Message)的。其中Assert_INTx消息表示INTx信号的下降沿。Dessert_INTx消息表示INTx信号的上升沿。当发送这两种消息时,PCIe设备还会将配置空间的相关中断状态bit的值更新。对于PCIe-PCI(X)桥设备来说,会将接收到的来自PCI/PCI-X总线的INTx信号转换为消息,在往上级发送。一个简单的例子如下图所示:
INTx消息的格式为:
桥设备中的INTx消息的类型与设备号的映射关系如下图所示:
对应的,一个简单的例子如下:
当多个设备使用同一个中断信号线时,只有先置位的设备会被中断控制器响应。但是该中断信号线,并不会因为其中一个设备的中断请求得到响应便被清除,而是会等到所有的发送请求的设备的中断请求都得到了响应之后。如下图所示:
✨二、MSI机制介绍
MSI本质上是一种Memory Write,和PCIe总线中的Message概念没有什么关系。并且,MSI的Data Payload也是固定的,始终为1DW。
由于MSI也是从PCI总线继承而来的,因此MSI相关的寄存器也存在于配置空间中的PCI兼容部分(前256个字节)。如下图所示,MSI有四种类型:
1.32-bit Address: 在这种配置中,MSI寄存器使用32位地址空间。这意味着中断消息可以被发送到32位内存地址范围内的任何位置。这种类型是MSI的基础形式,适用于大多数标准的中断处理需求,并被广泛支持于多种硬件和操作系统之中。
2.64-bit Address: 为了支持更大的内存地址空间,MSI机制也可以配置为使用64位地址。这对于在具有大内存地址空间的64位系统中是必要的,以确保MSI消息能够被正确地定位到高于4GB的地址空间。选择64位地址使得中断消息有更大的灵活性和兼容性,特别是在物理内存较大的系统中。
3.32-bit Address with Per-Vector Masking: 这个类型在32位地址的基础上增加了每个向量屏蔽的能力。Per-Vector
Masking允许操作系统独立地控制每个中断向量的屏蔽或使能状态,这就提供了更细粒度的中断管理。借助于每向量屏蔽,操作系统能更有效地处理和优化中断处理流程,尤其是在需要精确控制中断响应的场合。
4.64-bit Address with Per-Vector Masking: 类似于32位地址版本,这个配置提供了64位的地址范围,并支持对每个中断向量的屏蔽。这意味着系统可以使用更广阔的内存地址空间,并能够独立控制每个MSI中断向量的启用或禁用。这种配置提供了最大的灵活性和控制能力,适用于需要大量中断向量和高度中断管理功能的高性能和大容量系统。
Message Control Register用于确定MSI的格式与支持的功能等信息,如下图所示:
具体描述如下:
Message Address Register:32-bit最低两位固定为0,使得该地址是DW对齐的。
当Mask Bits将相关的中断向量(Interrupt Vector)屏蔽后,该MSI将不会被发送。软件可以通过这种方式来使能或者禁止某些MSI的发送。如果相关中断向量没有被屏蔽,则如果发生了相关中断请求,这时Pending Bits中的相应bit则会被置位。一旦中断信息被发出,则该bit会立即被清零。
注:可能有的人会有疑惑了(无论是Mindshare的书,还是PCI的Spec都没有明确解释),因为Mask Bits和Pending Bits都只有32位,而8位的中断向量号最多可以表示256个!显然,32位最多只能对应32个中断向量号,无法支持256个的。实际上,一般的系统不会支持256个中断向量号的,32个就已经足够用了,所以并不用担心这个问题。
PCIe设备会根据配置空间中的MSI请求信息,来创建Memory Write TLP,来讲MSI信息发送出去。作为一种特殊的TLP,传递MSI的TLP需要遵循以下规则:
· No Snoop和Relaxed Ordering bits的值必须为0
· TLP长度值必须为01h
· First BE必须为1111b
· Last BE必须为0000b ·
地址是直接从配置空间中的响应位置复制过来的
如下图所示:
✨三、MSI-X机制介绍
PCI总线自3.0版本开始支持MSI-X机制,对MSI做出了一些升级和改进,以克服MSI机制的三个主要的缺陷:
1.随着系统的发展,对于特定的大型应用,32个中断向量不够用,如下图;
2.只有一个目标地址使得多核CPU情况下的,静态中断分配变得困难。如果能够使每个向量对应不同的唯一的地址,便会灵活很多;
3.某些应用中的中断优先级混乱问题。
👉3.1 MSI和MSI-X中断对比
有趣的是,MSI只支持32个中断向量,而MSI-X支持多达2048个中断向量,但是MSI-X的相关寄存器在配置空间中占用的空间却更小。这是因为中断向量信息并不直接存储在这里,而是在一款特殊的Memory(MIMO)中。并通过BIR(Base address Indicator Register, or BAR Index Register)来确定其在MIMO中的具体位置。如下图所示:
👉3.2 Message Control寄存器的具体描述如下:
📌 在 MSI-X Message Control Register 中的 Table Size字段指明了该设备支持的中断向量数量。该字段是一个11位宽的值,位于该寄存器的最低11位(位0到位10)。Table Size 的值决定了
MSI-X Table 所能容纳的条目数,直接对应于该设备能够使用的中断向量的数量。 Table Size的作用: 中断向量数量:
Table Size 字段的值加上1表示设备可以使用的中断向量的实际数量。例如如果 Table Size 的值为
0,则只有1个中断向量;如果值为 1,则有2个中断向量,以此类推。 MSI-X Table配置: 根据 Table Size
字段给出的向量数量,系统中的MSI-X
Table将进行相应的配置,每个向量对应表中一个条目,每个条目包括了中断消息地址和数据以及中断向量控制位。因此,Table Size
直接决定了 MSI-X Table 的大小。 资源分配和管理: 在系统初始化时,设备驱动或操作系统会检查 Table Size
的值来分配和管理所需的资源,比如内存空间及其他可能的系统资源,以确保每个中断向量可以被正确地配置和使用。 优化中断处理: Table
Size 的值影响着系统如何分配和处理中断。具有更多中断向量的设备能够为不同类型的事件分配独立中断,这有助于提高处理效率和减少中断处理时间。
👉3.3 MSI-X查找表的示意图如下:
👉3.4 结构图如下:
👉3.5 Pending Bits则位于另一个Memory中,其结构图如下:
MSI-X中断机制还使用了独立的Pending Table表,该表用来存放与每一个中断向量对应的Pending位。这个Pending位的定义与MSI Capability寄存器的Pending位类似。MSI-X Table和Pending Table存放在PCIe设备的BAR空间中。MSI-X机制必须支持这个Pending Table,而MSI机制的Pending Bits字段是可选的。
MSI-X(Message Signaled Interrupts eXtended)的Message Address字段定义了用于传递某个中断的目标内存地址。当PCI设备发生事件并需要向CPU发送中断时,它会写一个数据值到这个预先配置好的内存地址。下面是MSI-X Message Address字段的格式和详细解释:
MSI-X一条中断向量的完整表示通常包含两个关键部分:Message Address和Message Data。Message Address通常是64位的,在MSI-X的中断向量表中,它被划分为两个连续的32位寄存器(前32位和后32位)。在32位系统中可能只使用前32位。
在x86架构的系统中,Message Address通常包含以下部分:
高地址部分(上32位):通常固定为0xfee00000。这表示APIC(Advanced Programmable Interrupt Controller)的高速缓存一致性交换机的默认内存映射物理地址。
目标CPU指定:为了确保中断能被发送到正确的处理器,高地址部分还包含了目标CPU的ID或APIC ID。
下面是一个典型的64位Message Address格式,其中的组成部分:
0x FEE00000 || DestinationID || Reserved || TriggerMode || DeliverMode || Reserved
📌 字段解释
DestinationID:在高地址部分中,通常指示希望接收中断的目标CPU的ID。
Trigger Mode™:通常设置为固定值,指定中断触发模式。
(2’b00: PCIe设备使用边沿触发方式申请中断;2’b10:PCIe设备使用低电平触发方式申请中断; 2’b11: PCIe设备使用高电平触发方式申请中断)
Delivery Mode(DM):指定如何传送中断到本地APIC。
在某些情况下,可能不需要目标CPU指定和TriggerMode,特别是在具体实现于硬件或固件层面时。软件开发者和系统管理员通常无须关注这些位字段,因为它们在系统初始化时,由PCI配置空间的MSI-X Capabilities结构中正确设置。