本文将更偏向于具体编程实现的角度来介绍MSI-X,阅读本文需要有PCI总线以及MSI的基本前置知识。
MSI-X是PCI总线设备的一种中断方式,直接将中断投递到处理器核心的Local APIC。它与MSI的区别在于,MSI-X属于是对MSI中断的扩展,他们的区别在于,MSI的话,只有32个中断向量,且必须连续,MSI-X可以有2048个,可以不连续。
并且,MSI和MSI-X是互斥的,也就是说,对于某个pci设备而言,它要么启用MSI,要么启用MSI-X,不能同时启用二者。并且,有的PCI设备同时支持了二者,你可以选择启用其中的任意一种。
MSI-X Capability的结构
其中,DWORD0的低8bit为ID,若该部分的值为0x11,则表明当前链表结点为MSI-X Capability List
可以通过遍历PCI Config Space的Capability指针指向的链表,寻找CapabilityID为0x11的链表项,则为MSI-X的Capability空间,说明该设备支持MSI-X
该部分为指向下一个Capability List的指针。这个指针的值指的是下一个List item在PCI配置空间中的偏移量。
Message Control部分的bit分布
若当前位为1,且MSI Enable为0,那么,当前function将被允许使用MSI-X来进行中断请求。
当设备被reset之后,当前bit为0,默认是不开启MSI-X中断的
如当前位为1,则与该function相关的所有中断向量将会被屏蔽。若当前位为0,则当前function的每个中断向量的屏蔽情况由每个向量的单独的mask bit决定。
表明了MSI-X表的大小,这个部分是只读的。并且,这里它是“N-1”表示法的,举个例子,比如这里读到3,那么说明Table大小为4.
这个字段位于DWORD1的低3bits,表示哪个BAR寄存器中存储了MSI-X Table的地址,我们需要把对应的地址映射到虚拟内存之中。
它与具体的BAR寄存器具有以下映射关系:
BIR Value | 对应的BAR寄存器 | 寄存器偏移量 |
---|---|---|
0 | BAR0 | 0x10 |
1 | BAR1 | 0x14 |
2 | BAR2 | 0x18 |
3 | BAR3 | 0x1c |
4 | BAR4 | 0x20 |
5 | BAR5 | 0x24 |
再回头看pci标准中的header的结构,我们可以发现,对于PCI-to-PCI bridge,BIR的值只能选择0和1,因为bridge的其他部分都被用作了特殊用途。只有General device的是6个BAR都可用的。
该部分位于DWORD1,
MSI-X Table起始地址 = 在BIR中指定的BAR中存储的基地址+Table Offset
需要注意的是Table Offset是8bytes对齐的,它总共32bit,也就是说,把DWORD1的值读取出来,然后mask掉BIR,得到的就是Table Offset了。
该字段位于DWORD2中。它与上面的BIR类似,只不过它是用于指出Pending bit的基地址是存放在哪个寄存器之中。我们需要把对应的地址映射到虚拟内存之中。
这部分与上面的Table Offset类似,只不过涉及到的是MSI-X PBA
MSI-X Table中描述了该function的MSI-X中断向量。结构如下图所示:
MSi-X Table Structure
MSI-X表由最大2048个表项组成,每个表项占16bytes,最大占用32KB。
消息地址是4字节对齐的。
该字段指定了当中断发生时,用于驱动在Message Address上所进行的内存事务的数据,其中3:0bits被用于内存事务的数据阶段的assert。这一点和MSI的有些相像。但是不同的是,function不会修改Message data的低位。
这个字段位于DWORD3,只使用了第0bit,作为vector的mask bit,若被置位,那么这个function将不能使用这个表项来发送MSI-X中断。然而,需要注意的是:如果其他表项也使用了相同的中断向量号,他们仍然能被用来发送中断消息。
上面提到的Pending bits table,里边每个表项是64bits,每个bit对应了MSI-X Table中的一个表项。一旦对应的表项有中断产生,那么对应的pending bit就会被控制器置位。需要注意的是,系统软件不应该向pending bits写入数据,否则将产生未定义的结果。
在下文中,我们将介绍如何配置MSI-X中断。
转载请注明来源:https://longjin666.cn/?p=1496