MaxPayloadSize介绍
PCIe设备是以TLP的形式发送报文的,而max payload size(简称mps)决定了pcie设备实际使用的tlp能够传输的最大字节数。mps的大小是由PCIe链路两端的设备协商决定的,PCIe设备发送TLP时,其最大payload不能超过mps的值。
PCIE配置空间中的MaxPayloadSize
PCI有三个相互独立的物理地址空间:memory地址空间、I/O地址空间和配置空间。这三个地址空间都是采用唯一的地址进行寻址,比如我们使用地址0x100时需要指定这个地址在哪个地址空间(配置空间,I/O地址空间和memory地址空间的0x100偏移,对应的是不同的存储位置)。
PCIe设备的每一个功能(function)都对应一个独立的配置空间, pcie的配置空间布局如下图:
如上图所示,pci的配置空间是256字节,其中64字节是标准配置空间header, 后面的192字节是Capability结构, 展示pci能提供的能力。 为了兼容PCI,PCIe的配置空间前256字节与PCI保持一致,256~4096字节是pcie 扩展配置空间,包含pcie的扩展能力如AER。
其中MaxPayloadSize就在Capability结构中,如何查找到MaxPayloadSize?如下图为一个ep设备的64字节标准配置空间,其中偏移第34字节位置为Capability Pointer寄存器,通过此指针可以找到Capability部分。
标准配置空间header
Capbility Pointer寄存器: PCI capbility的地址偏移, capbility用于表示pci设备支持的能力。该寄存器存放Capabilities 结构链表的头指针。在一个PCIe 设备中,可能含有多个Capability 结构,这些寄存器组成一个链表:
Capbility结构组成如下图(这里个人理解并不是所有的Capbility都是下图的组成,只有Cap ID为0x10时才是下图的组成,因为每个Capbility所占的字节数并不相同,而且所包含的信息也不相同,具体应该要查协议),其中与MaxPayloadSize相关的寄存器有Device Capabilities和Device Control两个寄存器。
Device Capability 寄存器:
该寄存器的第 2:0 字段为 “ Max_Payload_Size Supported” 字段, 该字段存放该设备支持的 Max_Payload_Size 参数的大小, 该字段只读,具体含义如下图。这里需要注意此值仅表示该设备可以使用的最大值并不是实际使用的值,实际使用的值在Device Control 寄存器中。
PCIe 设备支持的 Max_Payload_Size
Device Control 寄存器:
该寄存器的第7:5字段为Max_Payload_Size的值,该字段是可读写的,此值为链路两端的 PCIe 设备进行协商后确定使用的实际值。该寄存器 的具体含义如下图。
系统下配置空间的查看与设置
常用命令:
lspci -tv//查看pcie树
lspci -vvv -s [B:D.S] //查看具体设备的详细信息
lspci -xxx -s [B:D.S] //查看设备的整个配置空间,-x查看前64B,-xxx查看前256B,-xxxx查看4K
setpci -s 00:00.0 0x地址.W=0x值 //修改设备配置空间值,L4个字节,W2个字节,B一个字节
setpci -s 03:00.0 CAP_EXP+08.W=0x值 //CAP_EXP代表Cap ID为0x10的能力结构偏移,其中配置空间的各个属性偏移代表名字,可用setpci --dumpregs命令查看。
通过具体设备深入了解配置空间
如下图中12:00.0为pcie转usb的卡,下面就以此设备为例了解配置空间。
查看此设备的详细配置空间,如下图所示。在标准配置空间的0x34偏移处描述的为第一个Capbility结构的指针,通过此指针可以依次往下排查,一直找到Cap ID为0x10的Capbility。查找过程如下图中的紫色框(三列数据),第一列为配置空间的偏移,第二列为Cap ID,第三列为下一个Capbility的偏移。
下图中的粗蓝色框部分为Cap ID为0x10的Capbility,可看到Device Capability 寄存器的值为0x00008fc0(bit[2:0]为0b000),Device Control 寄存器的值为0x0800(bit[7:5]为0b000)。所以Max_Payload_Size Supported值为128B,Max_Payload_Size值为128字节。
通过此方法,不仅可以找到MaxPayloadSize也可以找到链路的链接状态等,在此就不赘述了。
直接查看解析出的设备信息,发现各个Capbility的偏移以及Max_Payload_Size的值与上述的分析一致。
修改设备的MaxPayloadSize
在平时设备的使用过程中,有可能遇到过数据通信错误(malformed tlp), 或者网卡/磁盘在进行数据读写时性能没有达到预期,这些都可能和pcie 的max payload size配置有关系。
注意:只能修改配置空间中Device Control 寄存器中MaxPayloadSize的值,不能修改Device Capability 寄存器中MaxPayloadSize的值,因为Device Capability 寄存器中MaxPayloadSize字段是只读的。
方法1:手动修改配置空间中Device Control寄存器
还是以上面的pcie转usb的卡为例,修改MaxPayloadSize值为256字节,即将Device Control寄存器的bit[7:5]改为0b001。修改后的结果如下图所示,其实只修改此设备的MaxPayloadSize是无法生效的,需要设置整条pcie链路上面的节点,非常繁琐,有时候设置也不生效,这个也是和硬件支持的能力相关联,所以有了下面的方法2。
方法2:修改grub(建议使用此方法)
在grub文件中添加pci=pcie_bus_perf参数,会自动将整个链路上的MaxPayloadSize值根据设备所支持的值调整为最大。