我希望所有对PCIe设备的读写请求都能被CPU缓存,但实际情况并非如此。以下是我对写回MMIO区域的假设:
我修改了MTRRs,使相应的MMIO区域变为写回模式。MMIO区域从0x0c7300000开始,长度为0x100000(1MB)。以下是不同策略下的
以下是使用不同策略进行8B写入的波形捕获。我使用集成逻辑分析仪(ILA)来捕获这些波形。请观察
1. 不可缓存:link -> 正确,1B x 8个数据包 2. 写组合:link -> 正确,8B x 1个数据包 3. 回写:link -> 不符合预期,1B x 8个数据包
系统配置如下。
- 对PCIe设备的写操作只会在缓存写回时发生。
- TLP负载的大小为缓存块大小(64B)。
- 对PCIe设备的写操作发生在每次对MMIO区域的写入中。
- TLP负载的大小为1B。
struct pcie_ioctl ioctl_control;
ioctl_control.bar_select = BAR_ID;
ioctl_control.num_bytes_to_write = atoi(argv[1]);
if (ioctl(fd, IOCTL_WRITE_0xFF, &ioctl_control) < 0) {
printf("ioctl failed\n");
}
设备驱动程序的一部分
case IOCTL_WRITE_0xFF:
{
int i;
char *buff;
struct pci_cdev_struct *pci_cdev = pci_get_drvdata(fpga_pcie_dev.pci_device);
copy_from_user(&ioctl_control, (void __user *)arg, sizeof(ioctl_control));
buff = kmalloc(sizeof(char) * ioctl_control.num_bytes_to_write, GFP_KERNEL);
for (i = 0; i < ioctl_control.num_bytes_to_write; i++) {
buff[i] = 0xff;
}
memcpy(pci_cdev->bar[ioctl_control.bar_select], buff, ioctl_control.num_bytes_to_write);
kfree(buff);
break;
}
我修改了MTRRs,使相应的MMIO区域变为写回模式。MMIO区域从0x0c7300000开始,长度为0x100000(1MB)。以下是不同策略下的
cat /proc/mtrr
结果。请注意,我将每个区域设置为独占。
不可缓存
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: uncachable
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
写合并
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: write-combining
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
写回
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: write-back
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
以下是使用不同策略进行8B写入的波形捕获。我使用集成逻辑分析仪(ILA)来捕获这些波形。请观察
pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid
被设置时的pcie_endpoint_litepcietlpdepacketizer_tlp_req_payload_dat
。您可以通过在这些波形示例中计算pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid
的数量来计算数据包的数量。1. 不可缓存:link -> 正确,1B x 8个数据包 2. 写组合:link -> 正确,8B x 1个数据包 3. 回写:link -> 不符合预期,1B x 8个数据包
系统配置如下。
- CPU: 英特尔 Xeon E5-2630 v4 @ 2.20GHz
- 操作系统: Linux内核版本4.15.0-38
- PCIe设备: Xilinx FPGA KC705,使用litepcie进行编程
相关链接
mempcy
在内核中被实现为rep movsb
(因为您的CPU足够新,支持ERMSB,这使得rep movsb
相当不错)。 - Peter Cordes