《PCI_SPEV_V3_0.pdf》6.8节
PCIe中MSI和MSI-X中断机制
PCIe学习笔记之MSI/MSI-x中断及代码分析
msix中断分析
MSI中断与Linux实现
ARM GICv3中断控制器
开发板资料:
分析的文件:
linux-4.4_rk3399\drivers\pci\host\pcie-rockchip.c
传统PCI设备的引脚中有4条线:INTA#、INTB#、INTC#、INTD#,"#"表示低电平有效,如下图所示:
PCI设备就像普通的设备一样,通过物理引脚发出中断信号:
在PCI设备的配置空间,它声明:通过INTA#、INTB#、INTC#还是INTD#发出中断。
配置空间有2个寄存器:Interrupt Pin、Interrupt Line,作用如下:
Interrupt Pin:用来表示本设备通过哪条引脚发出中断信号,取值如下
Interrupt Pin取值 | 含义 |
---|---|
0 | 不需要中断引脚 |
1 | 通过INTA#发出中断 |
2 | 通过INTB#发出中断 |
3 | 通过INTC#发出中断 |
4 | 通过INTD#发出中断 |
5~0xff | 保留 |
Interrupt Line:给软件使用的,PCI设备本身不使用该寄存器。软件可以写入中断相关的信息,比如在Linux系统中,可以把分配的virq(虚拟中断号)写入此寄存器。软件完全可以自己记录中断信息,没必要依赖这个寄存器。
INTx中断是电平触发,处理过程如下:
PCIe设备的配置空间也同样有这2个寄存器:Interrupt Pin、Interrupt Line,它们的作用跟PCI设备完全一样。
PCI总线上有INTA#~INTD#这些真实存在的引脚,但是PCIE总线上并没有这些引脚,PCIe设备怎么兼容INTx中断机制?
PCIe设备通过"INTx模拟"(PCI Compatible INTx Emulation)来实现传统的INTx中断,当设备需要发出中断时,它会发出特殊的TLP包:
TLP头部中,Message Code被用来区分发出的是哪类TLP包,为例"INTx模拟",有两类TLP包:
跟传统PCI设备类似,这个"INTx模拟"的处理过程也是一样的:
PCIe控制器内部接收到INTx的TLP包后,就会向GIC发出中断,最终导致CPU接收到中断信号。
对应的中断程序执行时,会读取PCIe控制器的寄存器,分辨发生的是INTA#~INTD#这4个中断的哪一个。
在PCI系统中,使用真实的引脚发出中断已经带来了不方便:
在PCI系统中,就已经引入了新的中断机制:MSI,Message Signaled Interrupts。
在初始PCI设备时,可以告诉它一个地址(主控芯片的地址)、一个数据:
流程及硬件框图如下:
capability的意思是"能力",PCI/PCIe设备可以提供各种能力,所以在配置空间里有寄存器来描述这些capability:
Capability示例图如下:
一个PCI设备是否支持MSI,需要读取配置空间的capability来判断: 有MSI capability的话就支持MSI机制。
在配置空间中,MSI capability用来保存:pci_addr、data。表示:PCI设备往这个pci_addr写入data,就可以触发中断。
有如下问题要确认:
MSI capability格式如下:
MSI Capability格式的含义如下:
Capability ID:对于MSI capability,它的ID为05H
Next Pointer:下一个capability的位置,00H表示这是最后一个capability
Message Control
位 | 域 | 描述 |
---|---|---|
8 | Per-vector masking capable | 是否支持屏蔽单个中断(vector): 1: 支持 0: 不支持 这是只读位。 |
7 | 64 bit address capable | 是否支持64位地址: 1: 支持 0: 不支持 这是只读位。 |
6:4 | Multiple Message Enable | 系统软件可以支持多少个MSI中断? PCI设备可以表明自己想发出多少个中断, 但是到底能发出几个中断? 由系统软件决定,它会写这些位,表示能支持多少个中断: 000: 系统分配了1个中断 001: 系统分配了2个中断 010: 系统分配了4个中断 011: 系统分配了8个中断 100: 系统分配了16个中断 101: 系统分配了32个中断 110: 保留值 111: 保留值 这些位是可读可写的。 |
3:1 | Multiple Message Capable | PCI设备可以表明自己想发出多少个中断: 000: 设备申请1个中断 001: 设备申请2个中断 010: 设备申请4个中断 011: 设备申请8个中断 100: 设备申请16个中断 101: 设备申请32个中断 110: 保留值 111: 保留值 这些位是只读的。 |
0 | MSI Enable | 使能MSI: 1: 使能 0: 禁止 |
Message Address/Message Uper Address:地址
Message Data:数据
Mask Bits/Pending Bits: 屏蔽位/挂起位,这是可选的功能,PCI设备不一定实现它
MSI机制有几个缺点:
于是引入了MSI-X机制:Enhanced MSI interrupt support,它解决了MSI的缺点:
假设MSI-X可以支持很多中断,每个中断的"地址/数据"都不一样。提问:在哪里描述这些信息?
一个PCI设备是否支持MSI-X,需要读取配置空间的capability来判断: 有MSI-X capability的话就支持MSI-X机制。
MSI-X capability格式如下:
格式解析如下:
Capability ID:对于MSI-X capability,它的ID为11H
Next Pointer:下一个capability的位置,00H表示这是最后一个capability
Message Control
位 | 名 | 描述 |
---|---|---|
15 | MSI-X Enable | 是否使能MSI-X: 1: 使能 0: 禁止 注意: MSI-X和MSI不能同时使能。 |
14 | Function Mask | 相当于MSI-X中断总开关: 1: 所有中断禁止 0: 有各个中断的Mask位决定是否使能对应中断 |
13 | 保留 | |
10:0 | Table Size | 系统软件读取这些位,算出MSI-X Table的大小,也就是支持多少个中断 读出值为"N-1",表示支持N个中断 |
Table Offset/Table BIR :BIR意思为"BAR Indicator register",表示使用哪个BAR。
位 | 域 | 描述 |
---|---|---|
31:3 | Table Offset | MSI-X Table保存在PCI设备的内存空间里, 在哪个内存空间?有下面的"Table BIR"表示。 在这个内存空间的哪个位置?由当前这几位表示。 |
2:0 | Table BIR | 使用哪个内存空间来保存MSI-X Table? 也就是系统软件使用哪个BAR来访问MSI-X Table? 取值为05,表示BAR0BAR5 |
PBA Offset/PBA BIR:PBA意思为"Pending Bit Array",用来表示MSI-X中断的挂起状态。
位 | 域 | 描述 |
---|---|---|
31:3 | PBA Offset | PBA保存在PCI设备的内存空间里, 在哪个内存空间?有下面的"PBA BIR"表示。 在这个内存空间的哪个位置?由当前这几位表示。 |
2:0 | PBA BIR | 使用哪个内存空间来保存PBA? 也就是系统软件使用哪个BAR来访问PBA? 取值为05,表示BAR0BAR5 |
PCI设备可以往某个地址写入某个数据,从而触发MSI-X中断。
这些"地址/数据"信息,是由系统软件分配的,系统软件要把"地址/数据"发给PCI设备。
PCI设备在哪里保存这些信息?
MSI-X Table格式如何?如下图所示:
上图中,Msg Data、Msg Addr Msg Upper Addr含义与MSI机制相同:PCI设备要发出MSI-X中断时,往这个地址写入这个数据。如果使用32位地址的话,写哪个地址由Msg Addr寄存器决定;如果使用64位地址的话,写哪个地址由Msg Addr和Msg Upper Addr这两个寄存器决定。
Vector Control寄存器中,只有Bit0有作用,表示"Mask Bit"。系统软件写入1表示禁止对应中断,写入0表示使能对应中断。
PBA意思为"Pending Bit Array",用来表示MSI-X中断的挂起状态。它的格式如下:
这些"挂起"信息,是由PCI设备设置,系统软件只能读取这些信息。
PCI设备在哪里保存这些信息?
PBA格式如下:每一位对应一个中断,值为1表示中断发生了、等待处理。
扫描设备,读取capability,确定是否含有MSI capability、是否含有MSI-X capability。
一个设备,可能都支持INTx、MSI、MSI-X,这3中方式只能选择一种。
系统软件读取MSI capability,确定设备想申请多少个中断。
系统软件确定能分配多少个中断给这个设备,并把"地址/数据"写入MSI capability。
如果MSI capability支持中断使能的话,还需要系统软件设置MSI capability来使能中断。
注意:如果支持多个MSI中断,PCI设备发出中断时,写的是同一个地址,但是数据的低位可以发生变化。
比如支持4个MSI中断时,通过数据的bit1、bit0来表示是哪个中断。
MSI-X机制中,中断相关的更多信息保存在设备的内存空间。所以要使用MSI-X中断,要先配置设备、分配内存空间。
然后,系统软件读取MSI-X capability,确定设备需要多少个中断。
系统软件确定能分配多少个中断给这个设备,并把多个"地址/数据"写入MSI-X Table。
注意:PCI设备要发出MSI-X中断时,它会往"地址"写入"数据",这些"地址/数据"一旦配置后是不会变化的。MSI机制中,数据可以变化,MSI-X机制中数据不可以变化。
使能中断:设置总开关、MSI-X Table中某个中断的开关。
注意:MSI-X Table中,每一项都可以保存一个"地址/数据",Table中"地址/数据"可以相同,也就是说:PCI设备发出的中断可以是同一个。
PCI设备发出MSI中断、MSI-X中断时,都是发起"数据写"传输,就是往指定地址写入指定数据。
PCI控制器接收到数据后,就会触发CPU中断。
系统软件执行中断处理函数。
以上笔记源自
韦东山
老师的视频课程,感谢韦老师,韦老师是嵌入式培训界一股清流,为嵌入式linux开发点起的星星之火,也愿韦老师桃李满园。聚是一团火,散是满天星!
在这样一个速食的时代,坚持做自己,慢下来,潜心琢磨,心怀敬畏,领悟知识,才能向下扎到根,向上捅破天,背着世界往前行!
仅此向嵌入行业里的每一个认真做技术的从业者致敬!