写在前面
笔者在工作中需要包个 PCIe wrapper,正在努力飞快学习 PCIe ing.
本文系转载,略做格式调整与增加解释(使用斜体表示),转自:
http://blog.chinaaet.com/justlxy/p/5100057779
转载正文
两种中断传递方式
为了能够让一些优先级高的事务得到优先处理,PCI总线支持外设中断用以提高总线性能。
PCIe总线继承了PCI总线的所有中断特性(包括INTx和MSI/MSI-X),以兼容早期的一些PCI应用层软件。本次连载的文章只是简单的介绍PCIe中断的一些基本概念和特性,如需深入了解PCI/PCIe总线的中断内容,请参阅PCI/PCI-X Spec或者Mindshare的书籍(PCI System Architecture)。
PCI总线最早采用的中断机制是INTx,这是基于边带信号的。
后续的PCI/PCI-X版本,为了消除边带信号,降低系统的硬件设计复杂度,逐渐采用了MSI/MSI-X(消息信号中断)的中断机制。
INTx一般被称为传统的(Legacy)PCI中断机制,每个PCI设备最多支持四个中断信号(边带信号,INTA#、INTB#、INTC#和INTD#)。一个简单的例子如下图所示:
也可以参考一下之前的文章(关于INTx的):http://blog.chinaaet.com/justlxy/p/5100053096
MSI/MSI-X是后续的PCI/PCI-X总线改进后的中断机制,其中MSI-X(MSI-eXtented)是PCI-X中提出的升级版本。需要特别注意的是,MSI/MSI-X与PCIe总线中的消息(Message)的概念完全不同!MSI/MSI-X本质上是一种Posted Memory Write。
一个简单的例子如下图所示:
中断机制介绍(INTx)
一个简单的PCI总线INTx中断实现流程,如下图所示。
- 首先,PCI设备通过INTx边带信号产生中断请求,经过中断控制器(Interrupt Controller,PIC)后,转换为INTR信号,并直接发送至CPU;
- CPU收到INTR信号置位后,意识到了中断请求的发生,但是此时并不知道是什么中断请求。于是通过一个特殊的指令来查询中断请求信息,该过程一般被称为中断应答(Interrupt Acknowledge);
- 该特殊指令被发送至PIC后,PIC会返回一个8bits的中断向量(Interrupt Vector)值给CPU。该中断向量值与其发送的INTR请求是对应的;
- CPU收到来自PIC的中断向量值后,会去其Memory中的中断向量表(Interrupt Table)中查找对应的中断服务程序(Interrupt Service Routines,ISR)在Memory的位置;
- 然后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有四种类型:
其中Capability ID的值是只读的,05h表示支持MSI功能。
Next Capability Pointer也是只读的,其用于查找下一个Capability Structure的位置,其值为00h则表示到达Linked List的最后了。
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机制的三个主要的缺陷:
- 随着系统的发展,对于特定的大型应用,32个中断向量不够用了(参考前一篇文章);
- 只有一个目标地址使得多核CPU情况下的,静态中断分配变得困难。如果能够使每个向量对应不同的唯一的地址,便会灵活很多;
- 某些应用中的中断优先级混乱问题。
有趣的是,MSI只支持32个中断向量,而MSI-X支持多达2048个中断向量,但是MSI-X的相关寄存器在配置空间中占用的空间却更小。这是因为中断向量信息并不直接存储在这里,而是在一款特殊的Memory(MIMO)中。并通过BIR(Base address Indicator Register, or BAR Index Register)来确定其在MIMO中的具体位置。如下图所示:
Message Control寄存器的具体描述如下:
MSI-X查找表的示意图如下:
结构图如下:
类似的,Pending Bits则位于另一个Memory中,其结构图如下:
注:无论是MSI还是MSI-X,其本质上都是基于Memory Write 的,因此也可能会产生错误。
比如PCIe中的ECRC错误等。
版权声明
版权声明:本文为 AET 博主「Felix」的原创文章,转载请附上原文出处链接及本声明。
原文链接:http://blog.chinaaet.com/justlxy/p/5100053328
转载自:知乎
作者:Felix
推荐阅读
更多招聘及面经请关注FPGA的逻辑。