INTx_MSI_MSIX三种中断机制分析
文章目录
- INTx_MSI_MSIX三种中断机制分析
- 参考资料:
- 一、 PCI设备的INTx中断机制
- 二、 PCIe设备的INTx中断机制
- 三、 MSI中断机制
- 3.1 capability
- 3.2 MSI capability
- 3.3 格式解析
- 四、 MSI-X中断机制
- 4.1 MSI-X capability
- 4.2 MSI-X capability格式解析
- 4.3 MSI-X Table
- 4.4 PBA
- 五、MSI/MSI-X操作流程
- 5.1 扫描设备
- 5.2 配置设备
- 5.2.1 MSI配置
- 5.2.2 MSI-X配置
- 5.3 设备发出中断
- 5.4 中断函数
- 致谢
参考资料:
-
《PCI_SPEV_V3_0.pdf》6.8节
-
PCIe中MSI和MSI-X中断机制
-
PCIe学习笔记之MSI/MSI-x中断及代码分析
-
msix中断分析
-
MSI中断与Linux实现
-
ARM GICv3中断控制器
开发板资料:
- 开发板Firefly-rk3399资料
分析的文件:
linux-4.4_rk3399\drivers\pci\host\pcie-rockchip.c
一、 PCI设备的INTx中断机制
传统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中断是电平触发,处理过程如下:
- PCI设备发出中断:让INTx引脚变低
- 软件处理中断,清除中断:写PCI设备的某个寄存器,导致PCI设备取消中断
- PCI设备取消中断:让INTx引脚变高
二、 PCIe设备的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包:
- Assert_INTx
- Deassert_INTx
跟传统PCI设备类似,这个"INTx模拟"的处理过程也是一样的:
- PCIe设备发出中断:发出Assert_INTx的TLP包
- 软件处理中断,清除中断:写PCIe设备的某个寄存器,导致PCIe设备取消中断
- PCIe设备取消中断:发出Deassert_INTx的TLP包
硬件框图如下:
对于软件开发人员来说,他感觉不到变化:
- PCI设备通过真实的引脚传输中断
- PCIe设备通过TLP实现虚拟的引脚传输中断
PCIe控制器内部接收到INTx的TLP包后,就会向GIC发出中断,最终导致CPU接收到中断信号。
对应的中断程序执行时,会读取PCIe控制器的寄存器,分辨发生的是INTA#~INTD#这4个中断的哪一个。
三、 MSI中断机制
在PCI系统中,使用真实的引脚发出中断已经带来了不方便:
- 电路板上需要布线
- 只有4条引脚,多个PCI设备共享这些引脚,中断处理效率低。
在PCI系统中,就已经引入了新的中断机制:MSI,Message Signaled Interrupts。
在初始PCI设备时,可以告诉它一个地址(主控芯片的地址)、一个数据:
- PCI设备想发出中断时,往这个地址写入这个数据就可以触发中断
- 软件读到这个数据,就知道是哪个设备发出中断了
流程及硬件框图如下:
- 写哪个地址可以触发中断?可能是PCI/PCIe控制器里面的某个地址,也可能是GIC的某个地址
- 初始化PCI/PCIe设备时,把该地址(cpu_addr)转换为pci_addr,告知PCI/PCIe设备(写入它的配置空间)
- PCI/PCIe设备要发出中断时,会发起一个"写内存传输":往pci_addr写入数据value
- 这导致cpu_addr被写入数据value,触发中断
上图中的"pci_addr/value"保存在哪里?保存在设备的配置空间的capability里。
3.1 capability
capability的意思是"能力",PCI/PCIe设备可以提供各种能力,所以在配置空间里有寄存器来描述这些capability:
- 配置空间里有第1个capability的位置:Capabilities Pointer
- 它指向第1个capability的多个寄存器,这些寄存器也是在配置空间里
- 第1个capability的寄存器里,也会指示第2个capability在哪里
Capability示例图如下:
- 配置空间0x34位置,存放的是第1个capability的位置:假设是 A4H
- 在配置空间0xA4位置,找到第1个capability,capability的寄存器有如下约定
- 第1个字节表示ID,每类capability都有自己的ID
- 第2个字节表示下一个capability的位置,如果等于0表示这是最后一个capability
- 其他寄存器由capability决定,所占据的寄存器数量由capability决定
- 第1个capability里面,它表示下一个capability在5CH
- 在配置空间0x5C位置,找到第2个capability
- 第1个字节表示ID,第2个字节表示下一个capability的位置(图里是E0H)
- 其他字节由capability本身决定
- 在配置空间0xE0位置,找到第3个capability
- 第1个字节表示ID
- 第2个字节表示下一个capability的位置,这里是00H表示没有更多的capability了
- 其他字节由capability本身决定
3.2 MSI capability
一个PCI设备是否支持MSI,需要读取配置空间的capability来判断: 有MSI capability的话就支持MSI机制。
在配置空间中,MSI capability用来保存:pci_addr、data。表示:PCI设备往这个pci_addr写入data,就可以触发中断。
有如下问题要确认:
- pci_addr是32位、还是64位?
- 能触发几个中断?通过地址来分辨,还是通过数据来分辨?
- 这些中断能否屏蔽?
- 能否读出中断状态?
- 这个些问题,都由capability里面的"Message Control"决定。
MSI capability格式如下:
3.3 格式解析
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:地址
- 32位地址保存在Message Address中
- 64位地址:低32位地址保存在Message Address中,高32位地址保存在Message Uper Address中
- 这些地址是系统软件初始化PCI设备时分配的,系统软件把分配的地址写入这些寄存器
- 这些地址属于PCI地址空间
-
Message Data:数据
- 这个寄存器只有15位,PCI设备发出中断时数据是32位的,其中高16位数据为0
- 这个寄存器的数值是系统软件初始化设备时写入的
- 当PCI设备想发出中断是会发起一次写传输:
- 往Message Address寄存器表示的地址,写入Message Data寄存器的数据
- 如果可以发出多个中断的话,发出的数据中低位可以改变
- 比如"Multiple Message Enable"被设置为"010"表示可以发出4个中断
- 那么PCI设备发出的数据中bit1,0可以修改
-
Mask Bits/Pending Bits: 屏蔽位/挂起位,这是可选的功能,PCI设备不一定实现它
- Mask Bits:每一位用来屏蔽一个中断,被系统软件设置为1表示禁止对应的中断
- Pending Bits:每一位用来表示一个中断的状态,这是软件只读位,它的值为1表示对应中断发生了,待处理
四、 MSI-X中断机制
MSI机制有几个缺点:
- 每个设备的中断数最大是32,太少了
- 需要系统软件分配连续的中断号,很可能失败,也就是说设备想发出N个中断,但是系统软件分配给它的中断少于N个
- 通过MSI发出中断时,地址是固定的
于是引入了MSI-X机制:Enhanced MSI interrupt support,它解决了MSI的缺点:
- 可以支持多大2048个中断
- 系统软件可以单独设置每个中断,不需要分配连续的中断号
- 每个中断可以单独设置:PCI设备使用的"地址/数据"可以单独设置
假设MSI-X可以支持很多中断,每个中断的"地址/数据"都不一样。提问:在哪里描述这些信息?
- “地址/数据”:
- 不放在配置空间,空间不够
- 放在PCI设备的内存空间:哪个内存空间?哪个BAR?内存空间哪个位置(偏移地址)?
- 系统软件可以读写这些内存空间
- 中断的控制信息
- 使能/禁止?
- 地址是32位还是64位?
- 这些控制信息也是保存在PCI设备的内存空间
- 中断的状态信息(挂起?)
- 这些信息也是保存在PCI设备的内存空间
4.1 MSI-X capability
一个PCI设备是否支持MSI-X,需要读取配置空间的capability来判断: 有MSI-X capability的话就支持MSI-X机制。
MSI-X capability格式如下:
4.2 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
4.3 MSI-X Table
PCI设备可以往某个地址写入某个数据,从而触发MSI-X中断。
这些"地址/数据"信息,是由系统软件分配的,系统软件要把"地址/数据"发给PCI设备。
PCI设备在哪里保存这些信息?
- 在PCI设备的内存空间
- 在哪个内存空间?由MSI-X capability的"Table BIR"决定
- 在这个内存空间的哪个位置?由MSI-X capability的"Table Offset"决定
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表示使能对应中断。
4.4 PBA
PBA意思为"Pending Bit Array",用来表示MSI-X中断的挂起状态。它的格式如下:
这些"挂起"信息,是由PCI设备设置,系统软件只能读取这些信息。
PCI设备在哪里保存这些信息?
- 在PCI设备的内存空间
- 在哪个内存空间?由MSI-X capability的"PBA BIR"决定
- 在这个内存空间的哪个位置?由MSI-X capability的"PBA Offset"决定
PBA格式如下:每一位对应一个中断,值为1表示中断发生了、等待处理。
五、MSI/MSI-X操作流程
5.1 扫描设备
扫描设备,读取capability,确定是否含有MSI capability、是否含有MSI-X capability。
5.2 配置设备
一个设备,可能都支持INTx、MSI、MSI-X,这3中方式只能选择一种。
5.2.1 MSI配置
系统软件读取MSI capability,确定设备想申请多少个中断。
系统软件确定能分配多少个中断给这个设备,并把"地址/数据"写入MSI capability。
如果MSI capability支持中断使能的话,还需要系统软件设置MSI capability来使能中断。
注意:如果支持多个MSI中断,PCI设备发出中断时,写的是同一个地址,但是数据的低位可以发生变化。
比如支持4个MSI中断时,通过数据的bit1、bit0来表示是哪个中断。
5.2.2 MSI-X配置
MSI-X机制中,中断相关的更多信息保存在设备的内存空间。所以要使用MSI-X中断,要先配置设备、分配内存空间。
然后,系统软件读取MSI-X capability,确定设备需要多少个中断。
系统软件确定能分配多少个中断给这个设备,并把多个"地址/数据"写入MSI-X Table。
注意:PCI设备要发出MSI-X中断时,它会往"地址"写入"数据",这些"地址/数据"一旦配置后是不会变化的。MSI机制中,数据可以变化,MSI-X机制中数据不可以变化。
使能中断:设置总开关、MSI-X Table中某个中断的开关。
注意:MSI-X Table中,每一项都可以保存一个"地址/数据",Table中"地址/数据"可以相同,也就是说:PCI设备发出的中断可以是同一个。
5.3 设备发出中断
PCI设备发出MSI中断、MSI-X中断时,都是发起"数据写"传输,就是往指定地址写入指定数据。
PCI控制器接收到数据后,就会触发CPU中断。
5.4 中断函数
系统软件执行中断处理函数。
致谢
以上笔记源自
韦东山
老师的视频课程,感谢韦老师,韦老师是嵌入式培训界一股清流,为嵌入式linux开发点起的星星之火,也愿韦老师桃李满园。聚是一团火,散是满天星!文章来源:https://uudwc.com/A/gVy5e
在这样一个速食的时代,坚持做自己,慢下来,潜心琢磨,心怀敬畏,领悟知识,才能向下扎到根,向上捅破天,背着世界往前行!
仅此向嵌入行业里的每一个认真做技术的从业者致敬!文章来源地址https://uudwc.com/A/gVy5e